Svelte is a compiler-based UI framework that transforms declarative component code into efficient imperative JavaScript that surgically updates the DOM
The svelte/legacy module provides backward compatibility for Svelte 4 code running in Svelte 5. This module contains deprecated functions and types that bridge the gap between Svelte 4's class-based components and Svelte 5's function-based components.
Important: All exports from this module are deprecated and should only be used as temporary solutions during migration from Svelte 4 to Svelte 5. See the Svelte 5 migration guide for recommended modern patterns.
function createClassComponent<
Props extends Record<string, any>,
Exports extends Record<string, any>,
Events extends Record<string, any>,
Slots extends Record<string, any>
>(
options: ComponentConstructorOptions<Props> & {
component: ComponentType<SvelteComponent<Props, Events, Slots>> | Component<Props>;
}
): SvelteComponent<Props, Events, Slots> & Exports{ .api }
Creates a Svelte 4 compatible component instance from a component function, taking the same options as a Svelte 4 component constructor.
Parameters:
options - Component constructor options including:
target - The DOM element to mount the component toanchor - Optional element to render beforeprops - Component propertiescomponent - The component function to instantiatecontext - Context maphydrate - Whether to hydrate existing DOMintro - Whether to play intro transitionsReturns: A Svelte 4 style component instance with $set, $on, and $destroy methods
Status: Deprecated - Use this only as a temporary solution to migrate your imperative component code to Svelte 5.
Example:
import { createClassComponent } from 'svelte/legacy';
import MyComponent from './MyComponent.svelte';
// Svelte 4 style instantiation
const instance = createClassComponent({
target: document.getElementById('app'),
component: MyComponent,
props: {
name: 'World'
}
});
// Use Svelte 4 style methods
instance.$set({ name: 'Universe' });
instance.$on('click', (event) => {
console.log('Component clicked', event.detail);
});
// Clean up when done
instance.$destroy();Migration Guide:
In Svelte 5, use the mount() function instead:
// Svelte 5 way
import { mount } from 'svelte';
import MyComponent from './MyComponent.svelte';
const instance = mount(MyComponent, {
target: document.getElementById('app'),
props: {
name: 'World'
}
});
// Update props using the component's exported functions
// or use callback props instead of eventsfunction asClassComponent<
Props extends Record<string, any>,
Exports extends Record<string, any>,
Events extends Record<string, any>,
Slots extends Record<string, any>
>(
component: SvelteComponent<Props, Events, Slots> | Component<Props>
): ComponentType<SvelteComponent<Props, Events, Slots> & Exports>{ .api }
Wraps a Svelte 5 component function as a Svelte 4 compatible class component constructor.
Parameters:
component - A Svelte 5 component functionReturns: A constructor that can be instantiated with new like Svelte 4 components
Status: Deprecated - Use this only as a temporary solution to migrate your imperative component code to Svelte 5.
Example:
import { asClassComponent } from 'svelte/legacy';
import MyComponent from './MyComponent.svelte';
// Create a Svelte 4-style constructor
const ComponentClass = asClassComponent(MyComponent);
// Now can be used like Svelte 4 components
const instance = new ComponentClass({
target: document.getElementById('app'),
props: { count: 0 }
});
// Supports Svelte 4 methods
instance.$set({ count: 5 });
instance.$on('change', handler);
instance.$destroy();Use Case:
This is particularly useful when:
Migration Guide:
Refactor code to use mount() directly instead of relying on class instantiation:
// Before (Svelte 4)
const instance = new MyComponent({
target: element,
props: { value: 10 }
});
// After (Svelte 5)
import { mount } from 'svelte';
const instance = mount(MyComponent, {
target: element,
props: { value: 10 }
});function run(fn: () => void | (() => void)): void{ .api }
Runs the given function once immediately on the server, and works like $effect.pre on the client. Provides Svelte 4-style reactive behavior.
Parameters:
fn - Function to execute. Can optionally return a cleanup function.Status: Deprecated - Use this only as a temporary solution to migrate your component code to Svelte 5.
Example:
import { run } from 'svelte/legacy';
// Inside a component
run(() => {
console.log('This runs immediately on server, as $effect.pre on client');
// Cleanup function (optional)
return () => {
console.log('Cleanup when effect re-runs or component unmounts');
};
});Migration Guide:
Replace run() with appropriate Svelte 5 runes:
// Instead of run()
import { run } from 'svelte/legacy';
run(() => {
// Side effect code
return () => {
// Cleanup
};
});
// Use $effect.pre in Svelte 5
$effect.pre(() => {
// Side effect code
return () => {
// Cleanup
};
});For server-only code, use conditional logic:
import { onMount } from 'svelte';
// Server-side (runs during SSR)
if (typeof window === 'undefined') {
// Server code
}
// Client-side only
onMount(() => {
// Client code
});Svelte 4 used event modifiers like on:click|preventDefault which are not available in Svelte 5. These utilities provide functional alternatives.
function handlers(...handlers: EventListener[]): EventListener{ .api }
Combines multiple event listeners into a single listener function. Mimics the ability to have multiple listeners in Svelte 4.
Parameters:
...handlers - Variable number of event listener functionsReturns: A single event listener that calls all handlers in sequence
Status: Deprecated
Example:
<script>
import { handlers } from 'svelte/legacy';
function logEvent(e) {
console.log('Event:', e.type);
}
function trackEvent(e) {
analytics.track(e.type);
}
const handleClick = handlers(logEvent, trackEvent);
</script>
<button onclick={handleClick}>Click me</button>Migration Guide:
In Svelte 5, simply define a function that calls multiple handlers:
<script>
function handleClick(e) {
logEvent(e);
trackEvent(e);
}
</script>
<button onclick={handleClick}>Click me</button>function trusted(
fn: (event: Event, ...args: Array<unknown>) => void
): (event: Event, ...args: unknown[]) => void{ .api }
Substitute for the trusted event modifier. Only executes the handler if event.isTrusted is true (i.e., the event was triggered by user action, not programmatically).
Parameters:
fn - Event handler functionReturns: Wrapped handler that checks event.isTrusted
Status: Deprecated
Example:
<script>
import { trusted } from 'svelte/legacy';
function handleSubmit(e) {
// Only processes user-initiated submissions
console.log('Form submitted by user');
}
const onSubmit = trusted(handleSubmit);
</script>
<form onsubmit={onSubmit}>
<!-- ... -->
</form>Migration Guide:
<!-- Svelte 4 -->
<form on:submit|trusted={handleSubmit}>
<!-- Svelte 5 -->
<script>
function handleSubmit(e) {
if (!e.isTrusted) return;
// Handle trusted event
}
</script>
<form onsubmit={handleSubmit}>function self(
fn: (event: Event, ...args: Array<unknown>) => void
): (event: Event, ...args: unknown[]) => void{ .api }
Substitute for the self event modifier. Only executes the handler if event.target === event.currentTarget (i.e., the event originated on this element, not a child).
Parameters:
fn - Event handler functionReturns: Wrapped handler that checks if event target is the current target
Status: Deprecated
Example:
<script>
import { self } from 'svelte/legacy';
function handleDivClick(e) {
console.log('Div itself clicked, not child elements');
}
const onClick = self(handleDivClick);
</script>
<div onclick={onClick}>
Click the div background (not the button)
<button>Button</button>
</div>Migration Guide:
<!-- Svelte 4 -->
<div on:click|self={handleClick}>
<!-- Svelte 5 -->
<script>
function handleClick(e) {
if (e.target !== e.currentTarget) return;
// Handle click on element itself
}
</script>
<div onclick={handleClick}>function stopPropagation(
fn: (event: Event, ...args: Array<unknown>) => void
): (event: Event, ...args: unknown[]) => void{ .api }
Substitute for the stopPropagation event modifier. Calls event.stopPropagation() before executing the handler.
Parameters:
fn - Event handler functionReturns: Wrapped handler that stops event propagation
Status: Deprecated
Example:
<script>
import { stopPropagation } from 'svelte/legacy';
function handleButtonClick(e) {
console.log('Button clicked, event will not bubble to parent');
}
const onClick = stopPropagation(handleButtonClick);
</script>
<div onclick={() => console.log('This will not fire')}>
<button onclick={onClick}>Click me</button>
</div>Migration Guide:
<!-- Svelte 4 -->
<button on:click|stopPropagation={handleClick}>
<!-- Svelte 5 -->
<script>
function handleClick(e) {
e.stopPropagation();
// Handle click
}
</script>
<button onclick={handleClick}>function once(
fn: (event: Event, ...args: Array<unknown>) => void
): (event: Event, ...args: unknown[]) => void{ .api }
Substitute for the once event modifier. Ensures the handler only executes once, then removes itself.
Parameters:
fn - Event handler functionReturns: Wrapped handler that only fires once
Status: Deprecated
Example:
<script>
import { once } from 'svelte/legacy';
function handleFirstClick(e) {
console.log('This will only log once');
}
const onClick = once(handleFirstClick);
</script>
<button onclick={onClick}>Click me multiple times</button>Migration Guide:
<!-- Svelte 4 -->
<button on:click|once={handleClick}>
<!-- Svelte 5 -->
<script>
let clicked = $state(false);
function handleClick(e) {
if (clicked) return;
clicked = true;
// Handle first click
}
</script>
<button onclick={handleClick}>
<!-- Or use addEventListener with { once: true } -->
<script>
import { onMount } from 'svelte';
let button;
onMount(() => {
button.addEventListener('click', handleClick, { once: true });
});
</script>
<button bind:this={button}>function stopImmediatePropagation(
fn: (event: Event, ...args: Array<unknown>) => void
): (event: Event, ...args: unknown[]) => void{ .api }
Substitute for the stopImmediatePropagation event modifier. Calls event.stopImmediatePropagation() before executing the handler, preventing other listeners on the same element from firing.
Parameters:
fn - Event handler functionReturns: Wrapped handler that stops immediate propagation
Status: Deprecated
Example:
<script>
import { stopImmediatePropagation } from 'svelte/legacy';
function firstHandler(e) {
console.log('First handler - prevents other handlers');
}
function secondHandler(e) {
console.log('This will never fire');
}
const onClick1 = stopImmediatePropagation(firstHandler);
</script>
<button onclick={onClick1} onclick={secondHandler}>
Click me
</button>Migration Guide:
<!-- Svelte 4 -->
<button on:click|stopImmediatePropagation={handleClick}>
<!-- Svelte 5 -->
<script>
function handleClick(e) {
e.stopImmediatePropagation();
// Handle click
}
</script>
<button onclick={handleClick}>function preventDefault(
fn: (event: Event, ...args: Array<unknown>) => void
): (event: Event, ...args: unknown[]) => void{ .api }
Substitute for the preventDefault event modifier. Calls event.preventDefault() before executing the handler.
Parameters:
fn - Event handler functionReturns: Wrapped handler that prevents default behavior
Status: Deprecated
Example:
<script>
import { preventDefault } from 'svelte/legacy';
function handleSubmit(e) {
console.log('Form submitted without page reload');
}
const onSubmit = preventDefault(handleSubmit);
</script>
<form onsubmit={onSubmit}>
<input type="text" />
<button type="submit">Submit</button>
</form>Migration Guide:
<!-- Svelte 4 -->
<form on:submit|preventDefault={handleSubmit}>
<!-- Svelte 5 -->
<script>
function handleSubmit(e) {
e.preventDefault();
// Handle submit
}
</script>
<form onsubmit={handleSubmit}>Multiple modifiers can be combined:
<script>
import { preventDefault, stopPropagation, once } from 'svelte/legacy';
function handleClick(e) {
console.log('Handled with all modifiers');
}
// Combine multiple modifiers
const onClick = once(stopPropagation(preventDefault(handleClick)));
</script>
<button onclick={onClick}>Click me</button>
<!-- Migration to Svelte 5 -->
<script>
let clicked = $state(false);
function handleClick(e) {
if (clicked) return;
clicked = true;
e.preventDefault();
e.stopPropagation();
// Handle click
}
</script>
<button onclick={handleClick}>Click me</button>function passive(
node: HTMLElement,
[event, handler]: [event: string, handler: () => EventListener]
): void{ .api }
Substitute for the passive event modifier, implemented as an action. Adds an event listener with { passive: true } option, improving scrolling performance for touch/wheel events.
Parameters:
node - The HTML element to attach the listener to[event, handler] - Tuple of event name and handler functionStatus: Deprecated
Example:
<script>
import { passive } from 'svelte/legacy';
function handleScroll(e) {
// This listener won't block scrolling
console.log('Scrolled');
}
</script>
<div use:passive={['scroll', handleScroll]}>
Scrollable content
</div>Migration Guide:
<!-- Svelte 5 -->
<script>
import { onMount } from 'svelte';
let element;
onMount(() => {
element.addEventListener('scroll', handleScroll, { passive: true });
return () => {
element.removeEventListener('scroll', handleScroll);
};
});
function handleScroll(e) {
console.log('Scrolled');
}
</script>
<div bind:this={element}>
Scrollable content
</div>
<!-- Or create a reusable action -->
<script>
function passiveAction(node, { event, handler }) {
node.addEventListener(event, handler, { passive: true });
return {
destroy() {
node.removeEventListener(event, handler);
}
};
}
function handleScroll(e) {
console.log('Scrolled');
}
</script>
<div use:passiveAction={{ event: 'scroll', handler: handleScroll }}>
Scrollable content
</div>function nonpassive(
node: HTMLElement,
[event, handler]: [event: string, handler: () => EventListener]
): void{ .api }
Substitute for the nonpassive event modifier, implemented as an action. Adds an event listener with { passive: false } option, allowing preventDefault() in touch/wheel events.
Parameters:
node - The HTML element to attach the listener to[event, handler] - Tuple of event name and handler functionStatus: Deprecated
Example:
<script>
import { nonpassive } from 'svelte/legacy';
function handleTouchMove(e) {
// Can call preventDefault() to prevent scrolling
e.preventDefault();
console.log('Touch moved, scrolling prevented');
}
</script>
<div use:nonpassive={['touchmove', handleTouchMove]}>
Touch-interactive content
</div>Migration Guide:
<!-- Svelte 5 -->
<script>
import { onMount } from 'svelte';
let element;
onMount(() => {
element.addEventListener('touchmove', handleTouchMove, { passive: false });
return () => {
element.removeEventListener('touchmove', handleTouchMove);
};
});
function handleTouchMove(e) {
e.preventDefault();
console.log('Touch moved');
}
</script>
<div bind:this={element}>
Touch-interactive content
</div>function createBubbler(): (type: string) => (event: Event) => boolean{ .api }
Creates an event bubbling function that mimics the behavior of on:click without a handler in Svelte 4. This allows events to bubble up the component tree.
Returns: A function that takes an event type and returns an event handler
Status: Deprecated - Use this only as a temporary solution to migrate your automatically delegated events in Svelte 5.
Example:
<!-- Parent.svelte -->
<script>
import { createBubbler } from 'svelte/legacy';
import Child from './Child.svelte';
function handleClick(e) {
console.log('Event bubbled from child:', e.detail);
}
</script>
<Child on:customEvent={handleClick} />
<!-- Child.svelte -->
<script>
import { createBubbler } from 'svelte/legacy';
const bubble = createBubbler();
function handleInternalClick() {
// Bubble event to parent
const event = new CustomEvent('customEvent', {
detail: { data: 'hello' },
bubbles: true
});
bubble('customEvent')(event);
}
</script>
<button onclick={handleInternalClick}>Click to bubble</button>Migration Guide:
In Svelte 5, use callback props instead of event bubbling:
<!-- Parent.svelte (Svelte 5) -->
<script>
import Child from './Child.svelte';
function handleCustomEvent(detail) {
console.log('Event from child:', detail);
}
</script>
<Child onCustomEvent={handleCustomEvent} />
<!-- Child.svelte (Svelte 5) -->
<script>
let { onCustomEvent } = $props();
function handleInternalClick() {
onCustomEvent?.({ data: 'hello' });
}
</script>
<button onclick={handleInternalClick}>Click to notify parent</button>Or use event dispatching on the host element with $host():
<!-- Child.svelte (Svelte 5 with custom element) -->
<script>
function handleInternalClick() {
const host = $host();
host.dispatchEvent(new CustomEvent('customEvent', {
detail: { data: 'hello' },
bubbles: true
}));
}
</script>
<button onclick={handleInternalClick}>Click</button>type LegacyComponentType = {
new (o: ComponentConstructorOptions): SvelteComponent;
(...args: Parameters<Component<Record<string, any>>>): ReturnType<Component<Record<string, any>, Record<string, any>>>;
}{ .api }
A type that supports using a component as both a class (Svelte 4 style) and a function (Svelte 5 style) during the transition period.
Example:
import type { LegacyComponentType } from 'svelte/legacy';
import MyComponent from './MyComponent.svelte';
// Component can be used both ways
const ComponentAsClass: LegacyComponentType = MyComponent;
// Instantiate as class
const instance1 = new ComponentAsClass({
target: document.body,
props: { value: 10 }
});
// Or use as function (Svelte 5 style)
// Note: actual function usage happens through mount()class SvelteComponent<
Props extends Record<string, any> = Record<string, any>,
Events extends Record<string, any> = any,
Slots extends Record<string, any> = any
>{ .api }
Base class for Svelte 4 components. In Svelte 5, components are functions, not classes. This class is provided for backward compatibility and type checking.
Constructor:
constructor(options: ComponentConstructorOptions<Props>)Deprecated: This constructor only exists when using the asClassComponent compatibility helper. Migrate toward using mount instead.
Properties:
static element?: typeof HTMLElement - The custom element version (only present if compiled with customElement option)$$prop_def: Props - For type checking only, does not exist at runtime$$events_def: Events - For type checking only, does not exist at runtime$$slot_def: Slots - For type checking only, does not exist at runtime$$bindings?: string - For type checking only, does not exist at runtimeMethods:
$destroy(): voidDestroys the component, cleaning up listeners and DOM elements.
Deprecated: This method only exists when using legacy compatibility helpers.
Example:
const instance = new MyComponent({ target: document.body });
// Later...
instance.$destroy();$on<K extends Extract<keyof Events, string>>(
type: K,
callback: (e: Events[K]) => void
): () => voidAttaches an event listener. Returns an unsubscribe function.
Deprecated: This method only exists when using legacy compatibility helpers.
Example:
const instance = new MyComponent({ target: document.body });
const unsubscribe = instance.$on('change', (event) => {
console.log('Changed:', event.detail);
});
// Later...
unsubscribe();$set(props: Partial<Props>): voidUpdates component props programmatically.
Deprecated: This method only exists when using legacy compatibility helpers.
Example:
const instance = new MyComponent({
target: document.body,
props: { count: 0 }
});
// Update props
instance.$set({ count: 5 });Migration to Svelte 5:
// Svelte 4
const instance = new MyComponent({
target: document.body,
props: { count: 0 }
});
instance.$set({ count: 5 });
instance.$on('change', handler);
instance.$destroy();
// Svelte 5
import { mount, unmount } from 'svelte';
const instance = mount(MyComponent, {
target: document.body,
props: { count: 0 }
});
// Props are reactive - update through component's API
// Use callback props instead of $on
// Use unmount instead of $destroy
unmount(instance);interface ComponentConstructorOptions<
Props extends Record<string, any> = Record<string, any>
>{ .api }
Options for instantiating Svelte 4-style class components.
Properties:
target: Element | Document | ShadowRoot - Required. The DOM element to render the component intoanchor?: Element - Optional element to render immediately beforeprops?: Props - Initial component propertiescontext?: Map<any, any> - Context values accessible via getContext()hydrate?: boolean - If true, hydrate existing DOM instead of creating new elementsintro?: boolean - If true, play intro transitions on initial renderrecover?: boolean - If true, attempt to recover from errors during hydrationsync?: boolean - If true, flush updates synchronouslyidPrefix?: string - Prefix for element IDs (for SSR)$$inline?: boolean - Internal flag for inline componentsStatus: Deprecated - In Svelte 4, components are classes. In Svelte 5, they are functions. Use mount instead to instantiate components.
Example:
import type { ComponentConstructorOptions } from 'svelte';
import MyComponent from './MyComponent.svelte';
const options: ComponentConstructorOptions<{ count: number }> = {
target: document.getElementById('app'),
props: {
count: 0
},
intro: true,
context: new Map([['theme', 'dark']])
};
const instance = new MyComponent(options);Migration to Svelte 5:
Use MountOptions with the mount() function:
import { mount } from 'svelte';
import type { MountOptions } from 'svelte';
import MyComponent from './MyComponent.svelte';
const options: MountOptions<{ count: number }> = {
target: document.getElementById('app'),
props: {
count: 0
},
intro: true,
context: new Map([['theme', 'dark']])
};
const instance = mount(MyComponent, options);Here's a comprehensive example showing migration from Svelte 4 to Svelte 5 patterns:
<!-- Counter.svelte (Svelte 4) -->
<script>
import { createEventDispatcher } from 'svelte';
export let count = 0;
export let max = 10;
const dispatch = createEventDispatcher();
function increment() {
if (count < max) {
count += 1;
dispatch('change', { count });
}
}
function reset() {
count = 0;
dispatch('reset');
}
export function getValue() {
return count;
}
</script>
<div>
<p>Count: {count}</p>
<button on:click|preventDefault|stopPropagation={increment}>
Increment
</button>
<button on:click|once={reset}>Reset</button>
</div>// app.js (Svelte 4)
import Counter from './Counter.svelte';
const counter = new Counter({
target: document.getElementById('app'),
props: {
count: 5,
max: 20
}
});
counter.$on('change', (event) => {
console.log('Count changed:', event.detail.count);
});
counter.$on('reset', () => {
console.log('Counter reset');
});
// Update props
counter.$set({ max: 15 });
// Get exported value
const value = counter.getValue();
// Clean up
counter.$destroy();<!-- Counter.svelte (Svelte 5) -->
<script>
let {
count = $bindable(0),
max = 10,
onChange,
onReset
} = $props();
function increment(e) {
e.preventDefault();
e.stopPropagation();
if (count < max) {
count += 1;
onChange?.({ count });
}
}
let resetClicked = $state(false);
function reset(e) {
if (resetClicked) return;
resetClicked = true;
count = 0;
onReset?.();
}
export function getValue() {
return count;
}
</script>
<div>
<p>Count: {count}</p>
<button onclick={increment}>Increment</button>
<button onclick={reset}>Reset</button>
</div>// app.js (Svelte 5)
import { mount } from 'svelte';
import Counter from './Counter.svelte';
const counter = mount(Counter, {
target: document.getElementById('app'),
props: {
count: 5,
max: 20,
onChange: (detail) => {
console.log('Count changed:', detail.count);
},
onReset: () => {
console.log('Counter reset');
}
}
});
// Props are reactive through bindable
// Update via component's exported API or state
// Get exported value
const value = counter.getValue();
// Clean up
import { unmount } from 'svelte';
unmount(counter);// transition-helper.js
// Temporary bridge during migration
import { asClassComponent } from 'svelte/legacy';
import Counter from './Counter.svelte';
// Export a Svelte 4-compatible version
export const CounterCompat = asClassComponent(Counter);
// Can be used in legacy code
const instance = new CounterCompat({
target: document.getElementById('app'),
props: { count: 0 }
});
instance.$on('change', (e) => console.log(e.detail));
instance.$destroy();The legacy module should only be used as a temporary bridge. Create a migration plan to update all code to Svelte 5 patterns.
Event modifiers are straightforward to migrate:
// Create a utility module
// event-utils.js
export function withPreventDefault(handler) {
return (e) => {
e.preventDefault();
handler(e);
};
}
export function withStopPropagation(handler) {
return (e) => {
e.stopPropagation();
handler(e);
};
}
// Use in components
import { withPreventDefault } from './event-utils';
<button onclick={withPreventDefault(handleClick)}><!-- Before (Svelte 4) -->
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function notify() {
dispatch('notification', { message: 'Hello' });
}
</script>
<!-- After (Svelte 5) -->
<script>
let { onNotification } = $props();
function notify() {
onNotification?.({ message: 'Hello' });
}
</script>// Before (Svelte 4)
import Component from './Component.svelte';
const instance = new Component({
target: element,
props: { value: 10 }
});
// After (Svelte 5)
import { mount } from 'svelte';
import Component from './Component.svelte';
const instance = mount(Component, {
target: element,
props: { value: 10 }
});<!-- Component.svelte (Svelte 5) -->
<script>
let { value = $bindable(0) } = $props();
</script>
<!-- Parent can bind and update -->
<script>
let count = $state(0);
function updateCount() {
count = 10; // Automatically updates child
}
</script>
<Component bind:value={count} />
<button onclick={updateCount}>Update</button>// test-utils.js
import { asClassComponent } from 'svelte/legacy';
export function makeLegacyComponent(Component) {
if (process.env.LEGACY_MODE) {
return asClassComponent(Component);
}
return Component;
}
// Use in tests
import { makeLegacyComponent } from './test-utils';
import Counter from './Counter.svelte';
const Component = makeLegacyComponent(Counter);
const instance = new Component({
target: container,
props: { count: 0 }
});// legacy-events.js
import {
preventDefault,
stopPropagation,
once,
trusted
} from 'svelte/legacy';
export function composeModifiers(handler, modifiers) {
let composed = handler;
if (modifiers.includes('preventDefault')) {
composed = preventDefault(composed);
}
if (modifiers.includes('stopPropagation')) {
composed = stopPropagation(composed);
}
if (modifiers.includes('once')) {
composed = once(composed);
}
if (modifiers.includes('trusted')) {
composed = trusted(composed);
}
return composed;
}
// Usage
const handler = composeModifiers(handleClick, [
'preventDefault',
'stopPropagation'
]);
<button onclick={handler}>Click</button>// LegacyWrapper.js
import { createClassComponent } from 'svelte/legacy';
export class LegacyAdapter {
constructor(Component) {
this.Component = Component;
}
mount(options) {
return createClassComponent({
...options,
component: this.Component
});
}
}
// Usage
import { LegacyAdapter } from './LegacyWrapper';
import MyComponent from './MyComponent.svelte';
const adapter = new LegacyAdapter(MyComponent);
const instance = adapter.mount({
target: document.body,
props: { value: 10 }
});<!-- HybridComponent.svelte -->
<script>
// Support both Svelte 4 and 5 patterns
import { createEventDispatcher } from 'svelte';
// Svelte 4 style
export let value = 0;
const dispatch = createEventDispatcher();
// Svelte 5 style props (optional)
let { onChange } = $props() || {};
function handleChange(newValue) {
value = newValue;
// Support both patterns
dispatch('change', { value });
onChange?.({ value });
}
</script>Solution: Use asClassComponent to create a compatible wrapper:
import { asClassComponent } from 'svelte/legacy';
import MyComponent from './MyComponent.svelte';
const CompatComponent = asClassComponent(MyComponent);
export default CompatComponent;Solution: Use createBubbler or migrate to callback props:
import { createBubbler } from 'svelte/legacy';
const bubble = createBubbler();
// Bubble custom events
function handleInternalEvent(e) {
bubble('customEvent')(e);
}Solution: Use the legacy event modifier functions or migrate to manual checks:
import { preventDefault, stopPropagation } from 'svelte/legacy';
// Temporary solution
const handler = preventDefault(stopPropagation(handleClick));
// Better: Migrate to Svelte 5 pattern
function handleClick(e) {
e.preventDefault();
e.stopPropagation();
// Handle event
}Install with Tessl CLI
npx tessl i tessl/npm-svelte