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 — calls event.preventDefault() before running the handler
  • stopPropagation — calls event.stopPropagation(), preventing the event reaching the next element
  • stopImmediatePropagation — calls event.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 set passive: false
  • capture — fires the handler during the capture phase instead of the bubbling phase
  • once — remove the handler after the first time it runs
  • self — only trigger handler if event.target is the element itself
  • trusted — only trigger handler if event.isTrusted is true. 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
}>();
@deprecatedUse callback props and/or the `$host()` rune instead — see [migration guide](https://svelte.dev/docs/svelte/v5-migration-guide#Event-changes-Component-events)
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
}>();
@deprecatedUse callback props and/or the `$host()` rune instead — see [migration guide](https://svelte.dev/docs/svelte/v5-migration-guide#Event-changes-Component-events)
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
}>();
@deprecatedUse callback props and/or the `$host()` rune instead — see [migration guide](https://svelte.dev/docs/svelte/v5-migration-guide#Event-changes-Component-events)
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
}>();
@deprecatedUse callback props and/or the `$host()` rune instead — see [migration guide](https://svelte.dev/docs/svelte/v5-migration-guide#Event-changes-Component-events)
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 createEventDispatcher is deprecated:

<script lang="ts">
	export let let decrement: anydecrement;
	export let let increment: anyincrement;
</script>

<button on:click={let decrement: anydecrement}>decrement</button>
<button on:click={let increment: anyincrement}>increment</button>
<script>
	export let let decrement: anydecrement;
	export let let increment: anyincrement;
</script>

<button on:click={let decrement: anydecrement}>decrement</button>
<button on:click={let increment: anyincrement}>increment</button>