diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index cfb110aac6..cfa9bfd226 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -542,7 +542,7 @@ export default function dom( push_array(declaration.body.body, accessors); body.push(declaration); - if (options.customElement && component.tag != null) { + if (options.customElement) { const props_str = writable_props.reduce((def, prop) => { def[prop.export_name] = component.component_options.ceProps?.[prop.export_name] || {}; if (prop.is_boolean && !def[prop.export_name].type) { @@ -557,9 +557,13 @@ export default function dom( .join(','); const use_shadow_dom = component.component_options.shadowdom !== 'none' ? 'true' : 'false'; - body.push( - b`@_customElements.define("${component.tag}", @create_custom_element(${name}, ${JSON.stringify(props_str)}, [${slots_str}], [${accessors_str}], ${use_shadow_dom}));` - ); + if (component.tag != null) { + body.push( + b`@_customElements.define("${component.tag}", @create_custom_element(${name}, ${JSON.stringify(props_str)}, [${slots_str}], [${accessors_str}], ${use_shadow_dom}));` + ); + } else { + body.push(b`@create_custom_element(${name}, ${JSON.stringify(props_str)}, [${slots_str}], [${accessors_str}], ${use_shadow_dom});`); + } } return { js: flatten(body), css }; diff --git a/src/runtime/internal/Component.ts b/src/runtime/internal/Component.ts index b48017522f..4cc5f4f85e 100644 --- a/src/runtime/internal/Component.ts +++ b/src/runtime/internal/Component.ts @@ -392,6 +392,8 @@ export function create_custom_element( }); }); + Component.element = Class as any; + return Class; } diff --git a/src/runtime/internal/dev.ts b/src/runtime/internal/dev.ts index 323312437b..6e3b2e53d6 100644 --- a/src/runtime/internal/dev.ts +++ b/src/runtime/internal/dev.ts @@ -201,6 +201,9 @@ export class SvelteComponentDev extends SvelteComponent { */ $$slot_def: any; + /** The custom element version of the component. Only present if compiled with the `customElement` compiler option */ + static element?: typeof HTMLElement; + constructor(options: ComponentConstructorOptions) { if (!options || (!options.target && !options.$$inline)) { throw new Error("'target' is a required option"); @@ -317,11 +320,14 @@ export class SvelteComponentTyped< * * ``` */ -export type ComponentType = new ( +export type ComponentType = (new ( options: ComponentConstructorOptions< Component extends SvelteComponentTyped ? Props : Record > -) => Component; +) => Component) & { + /** The custom element version of the component. Only present if compiled with the `customElement` compiler option */ + element?: typeof HTMLElement +}; /** * Convenience type to get the props the given component expects. Example: diff --git a/test/custom-elements/samples/no-tag/test.js b/test/custom-elements/samples/no-tag/test.js index b364bc6bcc..b933d24c39 100644 --- a/test/custom-elements/samples/no-tag/test.js +++ b/test/custom-elements/samples/no-tag/test.js @@ -1,10 +1,9 @@ import * as assert from 'assert'; import { tick } from 'svelte'; import CustomElement from './main.svelte'; -import { create_custom_element } from 'svelte/internal'; export default async function (target) { - customElements.define('no-tag', create_custom_element(CustomElement, { name: {} }, [], [], true)); + customElements.define('no-tag', CustomElement.element); target.innerHTML = ''; await tick();