storybook
storybook copied to clipboard
Svelte: Work with Custom Elements API
Is your feature request related to a problem? Please describe Related to https://github.com/storybookjs/storybook/issues/14381
Setting customElement: true
in "svelteOptions" (like below) breaks the built-in <HOC>
, <PreviewRender>
, and <SlotDecorator>
components since they are not configured to work with as Custom Elements. (See "Illegal Constructor" in screenshot)

Example config (not working):
...
"svelteOptions": {
"preprocess": require("svelte-preprocess")(),
"loader": {
compilerOptions: {
customElement: true
}
}
},
...
Describe the solution you'd like
Setting customElement: true
in main.js should result in Storybook being able to render custom web components.
Describe alternatives you've considered I've tried the following custom webpack config, but it's not working (see error below). Perhaps someone can point me in the right direction
module.exports = {
"stories": [
"../stories/**/*.stories.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx|svelte)"
],
"addons": [
"@storybook/addon-links",
"@storybook/addon-essentials",
"@storybook/addon-interactions"
],
"framework": "@storybook/svelte",
"svelteOptions": {
"preprocess": require("svelte-preprocess")()
}
},
webpackFinal: async (config, { configType }) => {
// Custom loader for .svelte files at project root
config.module.rules.push({
test: /(src|stories).*\.svelte$/,
loader: require.resolve('svelte-loader'),
options: {
preprocess: require("svelte-preprocess")(),
loader: {
compilerOptions: { customElement: true }
}
}
});
// Return the altered config
return config;
},
}
Which results in the following error:
ERROR in ./src/components/forms/MultiSelect.svelte
Module build failed (from ./node_modules/svelte-loader/index.js):
Error: ParseError: Expected } (32:1241)
30:
31: function add_css(target) {
32: append_styles(target, "svelte-1t7dfnx", "input.svelte-1t7dfnx.svelte-1t7dfnx{cursor:pointer}label.svelte-1t7dfnx.svelte-1t7dfnx{display:block;cursor:pointer}label[for=\"dropdown-content\"].svelte-1t7dfnx.svelte-1t7dfnx{margin-bottom:.5rem}span.svelte-1t7dfnx.svelte-1t7dfnx{max-width:100%;cursor:pointer;width:100%;box-sizing:border-box}.dropdown.svelte-1t7dfnx.svelte-1t7dfnx{font-size:var(--font-size, .75rem);position:relative;display:inline-block;min-width:max-content;box-sizing:border-box;width:100%}.dropdown.svelte-1t7dfnx>span.svelte-1t7dfnx{display:block;padding:10px;border:2px solid black}.dropdown-content.svelte-1t7dfnx.svelte-1t7dfnx{white-space:nowrap;box-sizing:border-box;color:#414142;line-height:1.5;top:100%;left:0;z-index:1000;float:left;font-size:14px;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15);border-radius:4px;box-shadow:0 6px 12px rgba(0,0,0,.175);position:absolute;list-style-type:none;font-family:inherit;text-align:left;margin:0;padding:1em;display:none;width:fit-content}.dropdown.svelte-1t7dfnx:hover .dropdown-content.svelte-1t7dfnx{display:block}label.required.svelte-1t7dfnx.svelte-1t7dfnx::before{content:'* ';color:var( --alert-color, #bf0000 )}");
^
33: }
34:
at /Users/my.user/Development/abc-components-svelte/node_modules/svelte-loader/index.js:89:12
@ ./stories/component.stories.ts 102:0-69 153:15-26 165:15-26
@ ./stories sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx|svelte))$
@ ./generated-stories-entry.js
@ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/svelte/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/svelte/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js
ERROR in ./stories/decorators/MaxWidthDecorator.svelte
Module build failed (from ./node_modules/svelte-loader/index.js):
Error: ParseError: The keyword 'let' is reserved (18:1)
16:
17: function create_fragment(ctx) {
18: let div;
^
19: let current;
20: const default_slot_template = /*#slots*/ ctx[1].default;
at /Users/my.user/Development/abc-components-svelte/node_modules/svelte-loader/index.js:89:12
@ ./stories/component.stories.ts 103:0-70 158:13-30
@ ./stories sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx|svelte))$
@ ./generated-stories-entry.js
@ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/svelte/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/svelte/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js
ERROR in ./src/components/forms/Input.svelte
Module build failed (from ./node_modules/svelte-loader/index.js):
Error: ParseError: The keyword 'let' is reserved (29:1)
27:
28: function create_else_block(ctx) {
29: let input;
^
30: let mounted;
31: let dispose;
at /Users/my.user/Development/abc-components-svelte/node_modules/svelte-loader/index.js:89:12
@ ./stories/component.stories.ts 101:0-57 120:15-20 130:15-20 141:15-20
@ ./stories sync ^\.(?:(?:^|\/|(?:(?:(?!(?:^|\/)\.).)*?)\/)(?!\.)(?=.)[^/]*?\.stories\.(js|jsx|ts|tsx|svelte))$
@ ./generated-stories-entry.js
@ multi ./node_modules/@storybook/core-client/dist/esm/globals/polyfills.js ./node_modules/@storybook/core-client/dist/esm/globals/globals.js (webpack)-hot-middleware/client.js?reload=true&quiet=false&noInfo=undefined ./storybook-init-framework-entry.js ./node_modules/@storybook/svelte/dist/esm/client/preview/config-generated-config-entry.js ./node_modules/@storybook/svelte/dist/esm/client/docs/config-generated-config-entry.js ./node_modules/@storybook/addon-links/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-docs/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-actions/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-backgrounds/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-measure/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-outline/preview.js-generated-config-entry.js ./node_modules/@storybook/addon-interactions/preview.js-generated-config-entry.js ./.storybook/preview.js-generated-config-entry.js ./generated-stories-entry.js
Are you able to assist to bring the feature to reality? Probably not, which is why I opened this ticket, but willing to try to learn
Did you end up finding any workarounds to this? I am running into similar issues.
@shilman would you be able to provide any advice on this? I am experiencing the same problem. Is some setup using webpack needed?
<svelte:options customElement={{ tag: "primer-icon" }} />
This is my source - https://github.com/JacobWeinbren/Primer-Components
cc @JReinhold