Skip to content

Component Events

Emitting and Listening to Events

Control:

vue
<script lang="ts" setup>
const emit = defineEmits<{
  (evt: 'inc'): void;
  (evt: 'dec'): void;
}>();

function increment() {
  console.log('inner');
  emit('inc');
}

function decrement() {
  console.log('inner');
  emit('dec');
}
</script>

<template>
  <button @click="increment">Increment</button>
  <button @click="decrement">Decrement</button>
</template>
svelte
<script lang="ts">
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher();

  function increment() {
    console.log('inner');
    dispatch('inc');
  }

  function decrement() {
    console.log('inner');
    dispatch('dec');
  }
</script>

<button on:click={increment}>Increment</button>
<button on:click={decrement}>Decrement</button>
tsx
interface Props {
  onInc(): void;
  onDec(): void;
}

export function Control(props: Props) {
  const { onInc, onDec } = props;

  function increment() {
    console.log('inner');
    onInc();
  }

  function decrement() {
    console.log('inner');
    onDec();
  }

  return (
    <>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </>
  );
}

Usage:

vue
<script lang="ts" setup>
import Control from '~/components/Control.vue';

function increment() {
  console.log('outer');
}

function decrement() {
  console.log('outer');
}
</script>

<template>
  <Control @inc="increment" @dec="decrement" />
</template>
svelte
<script lang="ts">
  import Control from '$lib/components/Control.svelte';

  function increment() {
    console.log('outer');
  }

  function decrement() {
    console.log('outer');
  }
</script>

<Control on:inc={increment} on:dec={decrement} />
tsx
import { Control } from '~/components/Control';

export function App() {
  function increment() {
    console.log('outer');
  }

  function decrement() {
    console.log('outer');
  }

  return (
    <>
      <Control onInc={increment} onDec={decrement} />
    </>
  );
}

Event Arguments

Control:

vue
<script lang="ts" setup>
const emit = defineEmits<{
  (evt: 'inc', val: number): void;
}>();

function increment() {
  emit('inc', 7);
}
</script>

<template>
  <button @click="increment">Increment</button>
</template>
svelte
<script lang="ts">
  import { createEventDispatcher } from 'svelte';

  const dispatch = createEventDispatcher<{ inc: number }>();

  function increment() {
    dispatch('inc', 7);
  }
</script>

<button on:click={increment}>Increment</button>
tsx
interface Props {
  onInc(val: number): void;
}

export function Control(props: Props) {
  const { onInc } = props;

  function increment() {
    onInc(7);
  }

  return (
    <>
      <button onClick={increment}>Increment</button>
    </>
  );
}

Usage:

vue
<script lang="ts" setup>
import Control from '~/components/Control.vue';

const increment: InstanceType<typeof Control>['onInc'] = (val) => {
  console.log(val); // 7
};
</script>

<template>
  <Control @inc="increment" />
</template>
vue
<script lang="ts" setup>
import type { ComponentProps } from 'vue-component-type-helpers';
import Control from '~/components/Control.vue';

const increment: ComponentProps<typeof Control>['onInc'] = (val) => {
  console.log(val); // 7
};
</script>

<template>
  <Control @inc="increment" />
</template>
svelte
<script lang="ts">
  import type { ComponentEvents } from 'svelte';

  import Control from '$lib/components/Control.svelte';

  function increment(evt: ComponentEvents<Control>['inc']) {
    console.log(evt.detail); // 7
  }
</script>

<Control on:inc={increment} />
tsx
import type { ComponentProps } from 'react';

import { Control } from '~/components/Control';

export function App() {
  const increment: ComponentProps<typeof Control>['onInc'] = (val) => {
    console.log(val); // 7
  };

  return (
    <>
      <Control onInc={increment} />
    </>
  );
}

Released under the MIT License.