This is also a very common problem that I stumbled upon, and I want to share a solution that seems to be a better fit with Svelte 5. To generalize the problem a bit: you have a visual data (VD) and some kind of intermediate state (IS), which you want to two-way bind over a transformation: VD <-f-> IS
.
Check out getters/setters. The tutorial is really more complicated than it should be. Here's a simple version:
<script>
let a = $state(13)
const f = x => JSON.stringify({x});
const fInv = x => {try{return JSON.parse(x).x} catch(err){return NaN}};
let internal = {
get value() { return f(a)},
set value(newV) { a = fInv(newV) }
}
</script>
<input bind:value={internal.value} />
<input bind:value={a} />