ZL
About Articles Contact
Published on Sep 24, 2024
Filed under:
#javascript,
#svelte

Speed of Svelte reactive bindings vs keyboard events

Svelte’s reactive bindings execute slower than keydown, keypress, and input events, but faster than keyup events.

The order is as follows:

  • keydown
  • keypress
  • input
  • Svelte’s reactive bindings update here
  • keyup

You probably won’t need keyboard event listeners if you’re using Svelte’s bindings because the bindings are usually sufficient:

<script>
let value = ''
$: {
// Do something with value
}
</script>
<input bind:value />

But if you ever need them, there are a couple of ways to handle their difference.

  1. Defer execution
  2. Use keyup instead
  3. Don’t bind

Defer execution

The first method is to defer execution of the event handler — so event.target.value will use the same value from the Svelte binding.

The simplest way is with setTimeout:

<script>
let value = ''
function handleInput(event) {
setTimeout(_ => {
// Use value here
}, 0)
}
</script>
<input bind:value on:input={handleInput} />

An alternative way is to use setTimeout’s promise-variant to defer execution.

<script>
let value = ''
async function handleInput(event) {
await delay()
// Use value here
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
</script>
<input bind:value on:input={handleInput} />

But you cannot use Svelte’s built-in tick function. This triggers too quickly for some reason, so the binding would not be updated in the event listener.

<script>
import { tick } from 'svelte'
let value = ''
async function handleInput(event) {
await tick()
// value would not be updated yet
}
</script>
<input bind:value on:input={handleInput} />

Of course, debouncing works. This may be the ideal solution if you need to handle asynchronous tasks.

<script>
let value = ''
async function handleInput(event) {
// Use value here
}
</script>
<input bind:value on:input={debounce(handleInput, 200)} />

Use keyup

If you wish to skip the binding trouble, you can use keyup instead of other keyboard events. This assumes keyup works for what you’re trying to do.

<script>
let value = ''
async function handleKeyup(event) {
// Use value here
}
</script>
<input bind:value on:keyup={handleKeyup} />

Don’t bind

The third (perhaps most preferred) way is simply not to bind. To do this, we just set the initial value and adjust it whenever we need to.

<script>
let value = ''
async function handleInput(event) {
value = event.target.value
}
</script>
<input {value} on:input={handleInput} />
Note

Svelte doesn’t update the <input> element when value changes because value is only used for the initial value.

Wrapping up

That’s everything you need to know about the relationship between Svelte’s reactive bindings and event listeners.

This might change in Svelte 5, though I think it’s unlikely. I’ll update this article or write a new one when I play around with Svelte 5.

Have fun in the meantime!

Previous Forcing the future Next Don't try to make anyone happy

Join My Newsletter

I share what I’m learning on this newsletter: code, building businesses, and living well.

Sometimes I write about technical deep-dives, product updates, musings on how to live, and sometimes my struggles and how I’m breaking through.

Regardless of the type of content, I do my best to send you an update every week.

If you’re into making things and growing as a person, you’ll probably feel at home here.

“

Zell’s writing is very accessible to newcomers because he shares his learning experience. He covers current topics and helps all readers level up their web development skills. Must subscribe.

Chen Hui Jing
Chen Hui Jing — Web Developer
The Footer

General

Home About Contact Testimonials Tools I Use

Projects

Magical Dev School Splendid Labz

Socials

Youtube Instagram Tiktok Github Bluesky X

Follow Along

Email RSS
© 2013 - 2025 Zell Liew / All rights reserved / Terms