Svelte • Legacy APIs
on:
On this page
In runes mode, event handlers are just like any other attribute or prop.
In legacy mode, we use the on: directive:
<script lang="ts">
let let count: numbercount = 0;
function function (local function) handleClick(event: MouseEvent): voidhandleClick(event: MouseEventevent: MouseEvent) {
let count: numbercount += 1;
}
</script>
<button on:click={function (local function) handleClick(event: MouseEvent): voidhandleClick}>
count: {let count: numbercount}
</button><script>
let count = 0;
/** @param {MouseEvent} event */
function handleClick(event) {
count += 1;
}
</script>
<button on:click={handleClick}>
count: {count}
</button>Handlers can be declared inline with no performance penalty:
<button on:click={() => (count += 1)}>
count: {count}
</button>Add modifiers to element event handlers with the | character.
<form on:submit|preventDefault={handleSubmit}>
<!-- the `submit` event's default is prevented,
so the page won't reload -->
</form>The following modifiers are available:
preventDefault— callsevent.preventDefault()before running the handlerstopPropagation— callsevent.stopPropagation(), preventing the event reaching the next elementstopImmediatePropagation— callsevent.stopImmediatePropagation(), preventing other listeners of the same event from being fired.passive— improves scrolling performance on touch/wheel events (Svelte will add it automatically where it’s safe to do so)nonpassive— explicitly setpassive: falsecapture— fires the handler during the capture phase instead of the bubbling phaseonce— remove the handler after the first time it runsself— only trigger handler ifevent.targetis the element itselftrusted— only trigger handler ifevent.isTrustedistrue. I.e. if the event is triggered by a user action.
Modifiers can be chained together, e.g. on:click|once|capture={...}.
If the on: directive is used without a value, the component will forward the event, meaning that a consumer of the component can listen for it.
<button on:click>
The component itself will emit the click event
</button>It’s possible to have multiple event listeners for the same event:
<script lang="ts">
let count = 0;
function increment() {
count += 1;
}
function log(event: MouseEvent) {
console.log(event);
}
</script>
<button on:click={increment} on:click={log}>
clicks: {count}
</button><script>
let count = 0;
function increment() {
count += 1;
}
/** @param {MouseEvent} event */
function log(event) {
console.log(event);
}
</script>
<button on:click={increment} on:click={log}>
clicks: {count}
</button>Component events
Components can dispatch events by creating a dispatcher when they are initialised:
<script lang="ts">
import { function createEventDispatcher<EventMap extends Record<string, any> = any>(): EventDispatcher<EventMap>Creates an event dispatcher that can be used to dispatch component events.
Event dispatchers are functions that can take two arguments: name and detail.
Component events created with createEventDispatcher create a
CustomEvent.
These events do not bubble.
The detail argument corresponds to the CustomEvent.detail
property and can contain any type of data.
The event dispatcher can be typed to narrow the allowed event names and the type of the detail argument:
const dispatch = createEventDispatcher<{
loaded: null; // does not take a detail argument
change: string; // takes a detail argument of type string, which is required
optional: number | null; // takes an optional detail argument of type number
}>();
createEventDispatcher } from 'svelte';
const const dispatch: EventDispatcher<any>dispatch = createEventDispatcher<any>(): EventDispatcher<any>Creates an event dispatcher that can be used to dispatch component events.
Event dispatchers are functions that can take two arguments: name and detail.
Component events created with createEventDispatcher create a
CustomEvent.
These events do not bubble.
The detail argument corresponds to the CustomEvent.detail
property and can contain any type of data.
The event dispatcher can be typed to narrow the allowed event names and the type of the detail argument:
const dispatch = createEventDispatcher<{
loaded: null; // does not take a detail argument
change: string; // takes a detail argument of type string, which is required
optional: number | null; // takes an optional detail argument of type number
}>();
createEventDispatcher();
</script>
<button on:click={() => const dispatch: EventDispatcher
<"decrement">(type: "decrement", parameter?: any, options?: DispatchOptions | undefined) => boolean
dispatch('decrement')}>decrement</button>
<button on:click={() => const dispatch: EventDispatcher
<"increment">(type: "increment", parameter?: any, options?: DispatchOptions | undefined) => boolean
dispatch('increment')}>increment</button><script>
import { function createEventDispatcher<EventMap extends Record<string, any> = any>(): EventDispatcher<EventMap>Creates an event dispatcher that can be used to dispatch component events.
Event dispatchers are functions that can take two arguments: name and detail.
Component events created with createEventDispatcher create a
CustomEvent.
These events do not bubble.
The detail argument corresponds to the CustomEvent.detail
property and can contain any type of data.
The event dispatcher can be typed to narrow the allowed event names and the type of the detail argument:
const dispatch = createEventDispatcher<{
loaded: null; // does not take a detail argument
change: string; // takes a detail argument of type string, which is required
optional: number | null; // takes an optional detail argument of type number
}>();
createEventDispatcher } from 'svelte';
const const dispatch: EventDispatcher<any>dispatch = createEventDispatcher<any>(): EventDispatcher<any>Creates an event dispatcher that can be used to dispatch component events.
Event dispatchers are functions that can take two arguments: name and detail.
Component events created with createEventDispatcher create a
CustomEvent.
These events do not bubble.
The detail argument corresponds to the CustomEvent.detail
property and can contain any type of data.
The event dispatcher can be typed to narrow the allowed event names and the type of the detail argument:
const dispatch = createEventDispatcher<{
loaded: null; // does not take a detail argument
change: string; // takes a detail argument of type string, which is required
optional: number | null; // takes an optional detail argument of type number
}>();
createEventDispatcher();
</script>
<button on:click={() => const dispatch: EventDispatcher
<"decrement">(type: "decrement", parameter?: any, options?: DispatchOptions | undefined) => boolean
dispatch('decrement')}>decrement</button>
<button on:click={() => const dispatch: EventDispatcher
<"increment">(type: "increment", parameter?: any, options?: DispatchOptions | undefined) => boolean
dispatch('increment')}>increment</button>dispatch creates a CustomEvent. If a second argument is provided, it becomes the detail property of the event object.
A consumer of this component can listen for the dispatched events:
<script lang="ts">
import type Stepper = SvelteComponent<Record<string, any>, any, any>
const Stepper: LegacyComponentType
Stepper from './Stepper.svelte';
let let n: numbern = 0;
</script>
<const Stepper: LegacyComponentTypeStepper
on:decrement={() => let n: numbern -= 1}
on:increment={() => let n: numbern += 1}
/>
<p>n: {let n: numbern}</p><script>
import type Stepper = SvelteComponent<Record<string, any>, any, any>
const Stepper: LegacyComponentType
Stepper from './Stepper.svelte';
let let n: numbern = 0;
</script>
<const Stepper: LegacyComponentTypeStepper
on:decrement={() => let n: numbern -= 1}
on:increment={() => let n: numbern += 1}
/>
<p>n: {let n: numbern}</p>Component events do not bubble — a parent component can only listen for events on its immediate children.
Other than once, modifiers are not valid on component event handlers.
If you’re planning an eventual migration to Svelte 5, use callback props instead. This will make upgrading easier as
createEventDispatcheris deprecated:<script lang="ts"> export letlet decrement: anydecrement; export letlet increment: anyincrement; </script> <button on:click={let decrement: anydecrement}>decrement</button> <button on:click={let increment: anyincrement}>increment</button><script> export letlet decrement: anydecrement; export letlet increment: anyincrement; </script> <button on:click={let decrement: anydecrement}>decrement</button> <button on:click={let increment: anyincrement}>increment</button>