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();