Instead of attaching an event handler to every item in a list, you can attach ONE handler to the parent. This is called event delegation, and it's a powerful performance optimization.
The Problem with Individual Handlers
Imagine you have a list of 1000 items, each with a click handler:
svelte<!-- INEFFICIENT: 1000 event listeners! --> {#each items as item} <li onclick={() => handleClick(item.id)}>{item.name}</li> {/each}
This creates 1000 separate event listeners. That's a lot of memory and can slow down your app.
The Solution: Delegate to a Parent
Instead, put ONE handler on the parent and figure out which item was clicked:
svelte<script> let items = $state([ { id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }, { id: 3, name: 'Cherry' } ]); function handleListClick(event) { // Find the closest <li> element from wherever we clicked const li = event.target.closest('li'); if (!li) return; // Clicked somewhere else in the list const id = li.dataset.id; console.log('Clicked item:', id); } </script> <ul onclick={handleListClick}> {#each items as item} <li data-id={item.id}>{item.name}</li> {/each} </ul>
Why This Works
- When you click an
<li>, the event bubbles up to the<ul> - Our handler on
<ul>catches the event - We use
event.target.closest('li')to find which<li>was clicked - We read the data from
data-idattribute
Using closest() Safely
The closest() method is essential for delegation. It traverses up the DOM tree:
svelte<script> function handleClick(event) { // closest() finds the nearest ancestor (or self) matching the selector const card = event.target.closest('.card'); if (card) { // We clicked somewhere inside a card console.log('Card ID:', card.dataset.cardId); } } </script> <div onclick={handleClick} class="card-container"> {#each cards as card} <div class="card" data-card-id={card.id}> <h3>{card.title}</h3> <p>{card.description}</p> <button>Action</button> </div> {/each} </div>
Even if the user clicks the <button>, <h3>, or <p>, closest('.card') will find the parent card element.
When to Use Delegation
ā Good for:
- Lists with many items
- Dynamically added elements
- Reducing memory usage
- Handling events on elements that don't exist yet
ā Overkill for:
- A few static buttons
- Cases where you need different handlers per element
- Forms with complex validation