Let’s consider the example of a list component where we want to differently style the selected item.
Approach 1: Selection at List level
One way of doing it is to keep a variable at the level of the list that holds the selected item.
In this case, whenever we change the value of the selected item, Svelte reactivity will have to loop through all the items in the list to check which one is selected.
<script>
let items = $state(Array.from({ length: 5000 }, (_, i) => ({
id: i,
name: `Item ${i}`
})));
let selectedId = null;
function selectItem(id) {
selectedId = id;
}
</script>
<ul>
{#each items as item}
<li
class:selected={item.id === selectedId}
on:click={() => selectItem(item.id)}
>
{item.name}
</li>
{/each}
</ul>
<style>
li {
padding: 4px 8px;
cursor: pointer;
}
.selected {
background-color: #0077ff;
color: white;
}
</style>
In this approach, whenever selectedI
d changes, every list item is re-evaluated for rendering, since each item’s class:selected
expression depends on selectedI
d. With thousands of items, this quickly becomes inefficient.
Approach 2: Fine-grained selection per item
Another way is to give each item its own selected flag and still maintain a reference to the currently selected item at the list level.
When selection changes, we update only the old and new item. This means only two list items update instead of thousands.
<script>
let items = $state(Array.from({ length: 5000 }, (_, i) => ({
id: i,
name: `Item ${i}`,
selected: false
})));
let selectedItem = null;
function selectItem(item) {
if (selectedItem) {
selectedItem.selected = false;
}
item.selected = true;
selectedItem = item;
}
</script>
<ul>
{#each items as item}
<li
class:selected={item.selected}
on:click={() => selectItem(item)}
>
{item.name}
</li>
{/each}
</ul>
<style>
li {
padding: 4px 8px;
cursor: pointer;
}
.selected {
background-color: #0077ff;
color: white;
}
</style>
Here, only the previously selected and newly selected items update. This takes advantage of Svelte’s fine-grained reactivity and scales much better with thousands of items.
This distinction becomes critical when working with large datasets (lists, tables, tree views). I’ve found that many Svelte component libraries don’t optimize for this pattern, which is why they struggle with more than a few thousand items.