Basic Setup
To create a custom element, use thecustomElement option in <svelte:options>:
MyElement.svelte
svelte.config.js
Using Custom Elements
Once defined, use your component as a regular HTML element:Props are exposed as both DOM properties and HTML attributes (where possible).
Defining Custom Elements
Automatic Registration
WithcustomElement set to a tag name, the element auto-registers:
Manual Registration
Omit the tag name to register manually:MyElement.svelte
Advanced Configuration
Configure custom element behavior with an object:Configuration Options
tag
Optional tag name for auto-registration:
shadow
Configure the shadow DOM:
"open"(default): Shadow root withmode: "open""none": No shadow root (styles won’t be encapsulated)ShadowRootInitobject: Custom shadow root configuration
props
Configure how props map to attributes:
'String'(default): No conversion'Number': Parse as number'Boolean': Convert to boolean'Array': Parse as JSON array'Object': Parse as JSON object
You must explicitly list all props for them to be exposed as DOM properties. Using
let props = $props() without listing them individually won’t work.extend
Extend the custom element class for advanced features:
Accessing the Host Element
Use the$host rune to access the custom element:
Component Lifecycle
Creation Timing
Custom elements use a wrapper approach:1
connectedCallback)Updates and Batching
Updates are batched and applied on the next tick:Destruction
The Svelte component is destroyed on the next tick afterdisconnectedCallback:
Slots and Content Projection
Custom elements use native<slot> elements:
Card.svelte
Caveats and Limitations
Style Encapsulation
Styles are encapsulated in the shadow DOM by default:- Global styles (from
global.css) don’t apply inside custom elements :global()styles don’t escape the shadow DOM- Styles are inlined as JavaScript, not extracted to separate CSS files
Server-Side Rendering
Slot Differences
- Svelte’s
{#each}blocks don’t render slotted content multiple times - The deprecated
let:directive doesn’t work with custom elements - No parent-to-slot data passing mechanism
Context API
Context works within a custom element but not across custom element boundaries.
Naming Constraints
Avoid properties/attributes starting withon:
Browser Support
Custom elements work in all modern browsers. For older browsers:Testing Custom Elements
Test as standard DOM elements:When to Use Custom Elements
Good use cases:- Component libraries for non-Svelte apps
- Embedding Svelte in existing applications
- Framework-agnostic design systems
- Progressive enhancement of static HTML
- Server-side rendered applications
- Sharing components between Svelte apps (use regular components)
- Heavy data passing between components (context won’t work)