Search code examples
reactive-programmingsveltesvelte-3

How do I make Svelte update input components like React does?


I'm looking to sanitise user input on the fly. Consider this Svelte REPL example where we attempt to remove all x's that the user types. If you type an "x", the sanitised version is the same as the original, so it doesn't update, but the "x" is still displayed in the input field. Once you type another character, there is a change, so the field is updated with the "x" removed. Compare this to this React sandbox where the state is always properly reflected.

How do I get React's behaviour in Svelte?

One could technically work around this issue by writing to value in the toy example (e.g. by having a two-way binding instead: bind:value={value}). That would cause Svelte to update value twice, first with the wrong value which then does trigger the invalidation code and then a second time with the right value. In the scenario I'm dealing with, I'm reading from an Observable which are read-only, so that hack is not an option. You can play around with such an example in this Svelte REPL.


Solution

  • You can use beforeinput event:

    <script>
        let value = 'test';
    
        function sanitize(e) {
            if (e.data.includes('x')) e.preventDefault();
        }
    </script>
    
    <input
        value={value}
        on:beforeinput={sanitize}
    />
    

    Demo

    You can actually use the same pattern for any input to get behavior like in react, here is the example of controlled input