Search code examples
sveltecustom-elementsvelte-component

how to build a svelte customElement using @smui/dialog?


I want to build a svelte component which can be used along with React frameworks, after read svelte docs, I decide to build my Svelte component to svelte customElement, everything goes well until I used @smui/dialog, my code :

<svelte:options tag="charity-legal-agreement-element" />

<script lang="ts">
import Dialog, {Title, Content, Actions} from '@smui/dialog';
...
<Dialog
  bind:this={dialog}
  aria-labelledby="dialog-title"
  aria-describedby="dialog-content"
  on:MDCDialog:closed={deleteItem}
>
...
</Dialog>

rollup config:

svelte({
        preprocess: sveltePreprocess({ sourceMap: !production }),
        compilerOptions: {
            // enable run-time checks when not in production
            dev: !production,
            customElement: true
        },
        // customElement: true
    }),
    postcss({
        extract: true,
        minimize: true,
        use: [
          ['sass', {
            includePaths: [
              './src/theme',
              './node_modules',
              '../../node_modules',
            ]
          }]
        ]
      }),
     ...

the error from debug console:

enter image description here

index.mjs:1512 Uncaught TypeError: Illegal constructor
at new SvelteElement (index.mjs:1512)
at new Dialog (Dialog.svelte:56)
at create_fragment (index.svelte:53)
at init (index.mjs:1489)
at new Src (index.svelte:72)
at main.ts:13
at main.ts:18
SvelteElement   @   index.mjs:1512
Dialog  @   Dialog.svelte:56
create_fragment @   index.svelte:53
init    @   index.mjs:1489
Src @   index.svelte:72
(anonymous) @   main.ts:13
(anonymous) @   main.ts:18

if I remove @smui/dialog ,everything works fine, but I need the dialog as a base component, any idea is appreciated~


Solution

  • When building a custom element with Svelte, every component in your app needs to be compiled with the <svelte:options tag="custom-element-name-here" />, which makes it tricky to import components from another library.

    You could try using the web component implementation of Material UI instead, though it's not 1.0 yet:

    // main.js
    import App from './App.svelte';
    import '@material/mwc-dialog';
    
    const app = new App({
        target: document.body,
        props: {
            name: 'world'
        }
    });
    
    export default app;
    
    <!-- App.svelte -->
    <svelte:options tag="custom-element"/>
    
    <h1>Hello world</h1>
    <mwc-dialog heading="Test dialog" open="true">
        <div>
            Text goes here
        </div>
    </mwc-dialog>
    

    Another option is to not compile to custom elements and use svelte-adapter to use the components in a React application.