Skip to main content
Deprecated: Use callback props and/or the $host() rune instead. See the migration guide for details.
Creates an event dispatcher that can be used to dispatch component events. Event dispatchers create CustomEvent instances that do not bubble.

Signature

function createEventDispatcher<
  EventMap extends Record<string, any> = any
>(): EventDispatcher<EventMap>
return
EventDispatcher<EventMap>
An event dispatcher function

EventDispatcher

interface EventDispatcher<EventMap extends Record<string, any>> {
  <Type extends keyof EventMap>(
    ...args: null extends EventMap[Type]
      ? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
      : undefined extends EventMap[Type]
        ? [type: Type, parameter?: EventMap[Type] | null | undefined, options?: DispatchOptions]
        : [type: Type, parameter: EventMap[Type], options?: DispatchOptions]
  ): boolean;
}
type
string
required
The event name
detail
any
The event detail data. Type depends on the event type in the EventMap
options
DispatchOptions
Event options
options.cancelable
boolean
default:"false"
Whether the event can be cancelled with event.preventDefault()
return
boolean
Returns false if the event was cancelled with preventDefault(), otherwise true

Usage

Basic Event Dispatch

Create and dispatch simple events:
<!-- ChildComponent.svelte -->
<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  function handleClick() {
    dispatch('message', { text: 'Hello!' });
  }
</script>

<button onclick={handleClick}>
  Send message
</button>
<!-- ParentComponent.svelte -->
<script>
  import ChildComponent from './ChildComponent.svelte';

  function handleMessage(event) {
    console.log(event.detail.text); // 'Hello!'
  }
</script>

<ChildComponent on:message={handleMessage} />

Typed Event Dispatcher

Type your events for better IDE support and type safety:
// ChildComponent.svelte
import { createEventDispatcher } from 'svelte';

const dispatch = createEventDispatcher<{
  loaded: null;              // no detail argument
  change: string;            // detail argument of type string (required)
  optional: number | null;   // optional detail argument
  submit: { name: string; email: string }; // object detail
}>();

// TypeScript enforces correct usage:
dispatch('loaded');                    // ✓ OK
dispatch('change', 'new value');       // ✓ OK
dispatch('change');                    // ✗ Error: missing required detail
dispatch('optional', 42);              // ✓ OK
dispatch('optional');                  // ✓ OK
dispatch('submit', { name: 'John', email: 'john@example.com' }); // ✓ OK

Cancelable Events

Create events that can be cancelled:
<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  function handleSubmit() {
    // Dispatch cancelable event
    const cancelled = !dispatch('submit', { data: 'value' }, { cancelable: true });

    if (cancelled) {
      console.log('Submit was cancelled');
      return;
    }

    console.log('Submit was not cancelled');
  }
</script>

<button onclick={handleSubmit}>
  Submit
</button>
Parent component:
<script>
  import ChildComponent from './ChildComponent.svelte';

  function handleSubmit(event) {
    if (event.detail.data === 'invalid') {
      event.preventDefault();
    }
  }
</script>

<ChildComponent on:submit={handleSubmit} />

Event Forwarding

Forward events from child components:
<!-- Button.svelte -->
<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();
</script>

<button onclick={() => dispatch('click')}>
  <slot />
</button>
<!-- MiddleComponent.svelte -->
<script>
  import Button from './Button.svelte';
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  function handleClick() {
    // Re-dispatch the event
    dispatch('click');
  }
</script>

<Button on:click={handleClick}>Click me</Button>
Or use the shorthand syntax:
<!-- MiddleComponent.svelte -->
<script>
  import Button from './Button.svelte';
</script>

<!-- Forward the click event automatically -->
<Button on:click />

Event Characteristics

No Bubbling

Unlike DOM events, component events created with createEventDispatcher do not bubble:
<!-- Events only go one level up -->
<Grandparent>
  <Parent>
    <Child /> <!-- Event dispatched here -->
  </Parent> <!-- Must explicitly forward to reach Grandparent -->
</Grandparent>

CustomEvent Details

Dispatched events are CustomEvent instances:
<script>
  function handleEvent(event) {
    console.log(event instanceof CustomEvent); // true
    console.log(event.detail);                 // your event data
    console.log(event.bubbles);                // false
    console.log(event.cancelable);            // depends on options
  }
</script>

Migration to Svelte 5

In Svelte 5, component events are replaced with callback props:
<!-- Before (Svelte 4) -->
<script>
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  function handleClick() {
    dispatch('click', { data: 'value' });
  }
</script>
<!-- After (Svelte 5) -->
<script>
  let { onclick } = $props();

  function handleClick() {
    onclick?.({ data: 'value' });
  }
</script>
Parent usage:
<!-- Before -->
<Component on:click={handleClick} />

<!-- After -->
<Component onclick={handleClick} />

Notes

  • Must be called during component initialization
  • Events do not bubble - they only go one level up
  • Events are CustomEvent instances
  • The detail property contains your event data
  • Return value indicates whether the event was cancelled
  • Unlike DOM events, component events are synchronous
  • In Svelte 5, prefer callback props over createEventDispatcher

See Also