DEV Community

Tan Li Hau
Tan Li Hau

Posted on • Updated on

7 Event Modifiers in Svelte You Must Know

This is how you add event listener in Svelte

<script>
  function onClick(event) {
  }
</script>

<button on:click={onClick} />
Enter fullscreen mode Exit fullscreen mode

Under the hood, it is calling addEventListener() from the DOM API.

The addEventListener() takes in 2 parameters, the event type and the listener; and optionally takes in a 3rd parameter, which is the option object.

The option is where you can specify whether to set up the event listener in capture phase, or making it passive. But how do you pass in this option in Svelte?

...

Introducing the Event Modifiers!

Event Modifiers help pass in options to your addEventListener, as well as simplify common patterns in event listener.

Here are the 7 event modifiers you must know!

1. preventDefault

How often you need to call event.preventDefault() to prevent default behavior from the browser? prevent form from submitting, prevent browser disallow drag-and-drop, ...

The preventDefault modifier helps you do that easily.

<script>
  function onClick(event) {}
</script>

<button on:click|preventDefault={onClick} />
Enter fullscreen mode Exit fullscreen mode

This is equivalent of calling event.preventDefault() on the start of the event handler

<script>
  function onClick(event) {}

  function onClickEquivalent(event) {
    event.preventDefault();
    onClick(event);
  }
</script>

<button on:click={onClickEquivalent} />
Enter fullscreen mode Exit fullscreen mode

2. stopPropagation

Have you used event.stopPropagation to prevent event from bubbling up to its parents?

You can easily do that with the stopPropagation modifier!

<script>
  function onClick(event) {}
</script>

<button on:click|stopPropagation={onClick} />
Enter fullscreen mode Exit fullscreen mode

This is equivalent of calling event.stopPropagation() on the start of the event handler

<script>
  function onClick(event) {}

  function onClickEquivalent(event) {
    event.stopPropagation();
    onClick(event);
  }
</script>

<button on:click={onClickEquivalent} />
Enter fullscreen mode Exit fullscreen mode

3. passive

For performance reasons, you may want to specify { passive: true } to indicate to the browser that you will not call event.preventDefault(). This is often used to improve the scrolling performance for scroll event listener

You can do this with the passive modifier

<script>
  function onScroll(event) {}
</script>

<div on:scroll|passive={onScroll} />
Enter fullscreen mode Exit fullscreen mode

This is equivalent of calling addEventListener() with { passive: true }

<script>
  function onScroll(event) {}

  let element;
  onMount(() => {
    element.addEventListener('scroll', onScroll, { passive: true });

    return () => {
      element.removeEventListener('scroll', onScroll, { passive: true });
    }
  });
</script>

<div bind:this={element} />
Enter fullscreen mode Exit fullscreen mode

4. nonpassive

passive: true is great, and Chrome is making them passive by default if you do not pass in the option for passive.

If you want to opt this out, you'll have to specify { passive: false }

which leads to the nonpassive event modifier

<script>
  function onScroll(event) {}
</script>

<div on:scroll|nonpassive={onScroll} />
Enter fullscreen mode Exit fullscreen mode

This is equivalent of calling addEventListener() with { passive: false }

<script>
  function onScroll(event) {}

  let element;
  onMount(() => {
    element.addEventListener('scroll', onScroll, { passive: false });

    return () => {
      element.removeEventListener('scroll', onScroll, { passive: false });
    }
  });
</script>

<div bind:this={element} />
Enter fullscreen mode Exit fullscreen mode

5. once

Sometimes you want the event listener to be called only once. You want to remove the event listener as soon as it's being called.

The once modifier helps you do that

<script>
  function onClick(event) {}
</script>

<button on:click|once={onClick} />
Enter fullscreen mode Exit fullscreen mode

This is equivalent of calling addEventListener() with { once: true }

<script>
  function onClick(event) {}

  let element;
  onMount(() => {
    element.addEventListener('click', onClick, { once: true });

    return () => {
      element.removeEventListener('click', onClick, { once: true });
    }
  });
</script>

<button bind:this={element} />
Enter fullscreen mode Exit fullscreen mode

6. capture

Sometimes, you want to register the event listener for the capturing phase.

You can do it with the capture event modifier

<script>
  function onClick(event) {}
</script>

<button on:click|capture={onClick} />
Enter fullscreen mode Exit fullscreen mode

This is equivalent of calling addEventListener() with { capture: true }

<script>
  function onClick(event) {}

  let element;
  onMount(() => {
    element.addEventListener('click', onClick, { capture: true });

    return () => {
      element.removeEventListener('click', onClick, { capture: true });
    }
  });
</script>

<button bind:this={element} />
Enter fullscreen mode Exit fullscreen mode

7. self

Lastly, you want the event listener to be called only when the event is dispatched from the element itself, and NOT from its children.

You do that with the self event modifier

<script>
  function onClick(event) {}
</script>

<button on:click|self={onClick} />
Enter fullscreen mode Exit fullscreen mode

This is equivalent of checking if the event.target === current element

<script>
  function onClick(event) {}

  let element;
  function onClickEquivalent(event) {
    if (event.target === element) {
      onClick(event);
    }
  }
</script>

<button bind:this={element} on:click={onClickEquivalent} />
Enter fullscreen mode Exit fullscreen mode

Event modifiers can be chained

There are times where you want to apply more than 1 event modifiers, and YES you can do that.

<button on:click|self|stopPropagation|preventDefault={onClick} />
Enter fullscreen mode Exit fullscreen mode

You can chain as many event modifiers as you like, and the order does not matter.

However, by the nature of passive and preventDefault, you can't use them together

<button on:click|passive|preventDefault={onClick} />
<!-- Error: The 'passive' and 'preventDefault' modifiers cannot be used together -->
Enter fullscreen mode Exit fullscreen mode

Do you learn better with video? I've made a video explaining how to add event listeners and cover each of the event modifiers in depth with examples

Discussion (1)

Collapse
opensas profile image
opensas

Excellent article as usual

Just a question, how can I use these event modifiers in my own components?

I want to make a custom button but I can't use these event modifiers, like this:

<MyButton on:click|preventDefault={clickHandler}>....
Enter fullscreen mode Exit fullscreen mode

Or at least how can I optionally apply those modifiers, so I can make something like

<MyButton prevenDefault on:click={clickHandler}>....
Enter fullscreen mode Exit fullscreen mode