Bindings
As a general rule, data flow in Svelte is top down — a parent component can set props on a child component, and a component can set attributes on an element, but not the other way around. Bindings is useful way in svelte to keep all value of variable or attribute that is bound together to stay the same. Here is type of bindings we can use.Text Input
If we want to bind value of text input we can use something like <inputbind:value={name}>. Below is some code example:
<script>
let name = 'world';
</script>
<input bind:value={name}>
<h1>Hello {name}!</h1>
Numeric Input
In the DOM, everything is a string. That's unhelpful when you're dealing with numeric inputs — type="number" and type="range"— as it means you have to remember to coerce input.value before using it.
With bind:value, Svelte takes care of it for you:
<script>
let a = 1;
let b = 2;
</script>
<label>
<input type=number bind:value={a} min=0 max=10>
<input type=range bind:value={a} min=0 max=10>
</label>
<label>
<input type=number bind:value={b} min=0 max=10>
<input type=range bind:value={b} min=0 max=10>
</label>
<p>{a} + {b} = {a + b}</p>
Checkbox Input
Checkboxes are used for toggling between states. Instead of binding to input.value, we bind to input.checked:
<input type=checkbox bind:checked={yes}>
Group Input
If you have multiple inputs relating to the same value, you can use bind:group along with the value attribute. Radio inputs in the same group are mutually exclusive; checkbox inputs in the same group form an array of selected values.
Add bind:group to each input. Here is some example:
<script>
let scoops = 1;
let flavours = ['Mint choc chip'];
let menu = [
'Cookies and cream',
'Mint choc chip',
'Raspberry ripple'
];
function join(flavours) {
if (flavours.length === 1) return flavours[0];
return `${flavours.slice(0, -1).join(', ')} and ${flavours[flavours.length - 1]}`;
}
</script>
<h2>Size</h2>
<label>
<input type=radio bind:group={scoops} value={1}>
One scoop
</label>
<label>
<input type=radio bind:group={scoops} value={2}>
Two scoops
</label>
<label>
<input type=radio bind:group={scoops} value={3}>
Three scoops
</label>
<h2>Flavours</h2>
{#each menu as flavour}
<label>
<input type=checkbox bind:group={flavours} value={flavour}>
{flavour}
</label>
{/each}
{#if flavours.length === 0}
<p>Please select at least one flavour</p>
{:else if flavours.length > scoops}
<p>Can't order more flavours than scoops!</p>
{:else}
<p>
You ordered {scoops} {scoops === 1 ? 'scoop' : 'scoops'}
of {join(flavours)}
</p>
{/if}
Textarea Input
The <textarea> element behaves similarly to a text input in Svelte — use bind:value=:
<textarea bind:value={value}></textarea>
In cases like these, where the names match, we can also use a shorthand form:
<textarea bind:value></textarea>
This applies to all bindings, not just textareas.
Select Binding
We can also use bind:value with <select> elements.
<script>
let questions = [
{ id: 1, text: `Where did you go to school?` },
{ id: 2, text: `What is your mother's name?` },
{ id: 3, text: `What is another personal fact that an attacker could easily find with Google?` }
];
let selected;
let answer = '';
function handleSubmit() {
alert(`answered question ${selected.id} (${selected.text}) with "${answer}"`);
}
</script>
<style>
input { display: block; width: 500px; max-width: 100%; }
</style>
<h2>Insecurity questions</h2>
<form on:submit|preventDefault={handleSubmit}>
<select bind:value={selected} on:change="{() => answer = ''}">
<!-- ^^^^ select binding here ^^^^ -->
{#each questions as question}
<option value={question}>{question.text}</option>
{/each}
</select>
<input bind:value={answer}>
<button disabled={!answer} type=submit>Submit</button>
</form>
<p>selected question {selected ? selected.id : '[waiting...]'}</p>
Note that the <option> values are objects rather than strings. Svelte doesn't mind.
Because we haven't set an initial value of selected, the binding will set it to the default value (the first in the list) automatically. Be careful though — until the binding is initialised, selected remains undefined, so we can't blindly reference e.g. selected.id in the template.
Select Multiple
A select can have a multiple attribute, in which case it will populate an array rather than selecting a single value.
Returning to our ice cream example in group binding , we can replace the checkboxes with a <select multiple>:
<h2>Flavours</h2>
<select multiple bind:value={flavours}>
{#each menu as flavour}
<option value={flavour}>
{flavour}
</option>
{/each}
</select>
Contenteditable Binding
Elements with a contenteditable="true" attribute support bind:textContent and bind:innerHTML bindings:
<script>
let html = '<p>Write some text!</p>';
</script>
<div
contenteditable="true"
bind:innerHTML={html}
></div> <!-- ^ innerHTML binding -->
<pre>{html}</pre>
<style>
[contenteditable] {
padding: 0.5em;
border: 1px solid #eee;
border-radius: 4px;
}
</style>
Without inner HTML bind in above example, changes in contenteditable wont automatically update text inside <pre> tag.
Each Block Binding
You can even bind to properties inside an each block.
<script>
let todos = [
{ done: false, text: 'finish Svelte tutorial' },
{ done: false, text: 'build an app' },
{ done: false, text: 'world domination' }
];
function add() {
todos = todos.concat({ done: false, text: '' });
}
function clear() {
todos = todos.filter(t => !t.done);
}
$: remaining = todos.filter(t => !t.done).length;
</script>
<style> .done { opacity: 0.4;} </style>
<h1>Todos</h1>
{#each todos as todo}
<div class:done={todo.done}>
<input
type=checkbox
bind:checked={todo.done} <!-- each binding -->
>
<input
placeholder="What needs to be done?"
bind:value={todo.text} <!-- each binding -->
>
</div>
{/each}
<p>{remaining} remaining</p>
<button on:click={add}>Add new </button>
<button on:click={clear}> Clear completed </button>
Media Element
The <audio> and <video> elements have several properties that you can bind to. This example demonstrates a few of them.
<video
poster="https://sveltejs.github.io/assets/caminandes-llamigos.jpg"
src="https://sveltejs.github.io/assets/caminandes-llamigos.mp4"
on:mousemove={handleMousemove}
on:mousedown={handleMousedown}
bind:currentTime={time}
bind:duration
bind:paused
></video>
Remember that bind:duration is equivalent to bind:duration={duration}. Now, when you click on the video, it will update time, duration and paused as appropriate. This means we can use them to build custom controls.
The complete set of bindings for <audio> and <video> is as follows — six readonly bindings...
- duration (readonly) — the total duration of the video, in seconds
- buffered (readonly) — an array of {start, end} objects
- seekable (readonly) — ditto
- played (readonly) — ditto
- seeking (readonly) — boolean
- ended (readonly) — boolean
...and four two-way bindings:
- currentTime — the current point in the video, in seconds
- playbackRate — how fast to play the video, where 1 is 'normal'
- paused — this one should be self-explanatory
- volume — a value between 0 and 1
Videos additionally have readonly videoWidth and videoHeight bindings. For complete interactive example of Media-Element binding you can check it here.
Dimensions
Every block-level element has bind:clientWidth, bind:clientHeight, bind:offsetWidth and bind:offsetHeight bindings:
<script>
let w;
let h;
let size = 42;
let text = 'edit me';
</script>
<style>
input { display: block; }
div { display: inline-block; }
span { word-break: break-all; }
</style>
<input type=range bind:value={size}>
<input bind:value={text}>
<p>size: {w}px x {h}px</p>
<div bind:clientWidth={w} bind:clientHeight={h}>
<span style="font-size: {size}px">{text}</span>
</div>
In the above example when we slide the slider it's automatically variable size, because we already bind the value with size variable. Then when size of text change, width and height of div element also automatically change, and bind with variable w and h respectively, so the text <p>size: {w}px x {h}px</p> also got updated.
This
The readonly this binding applies to every element (and component) and allows you to obtain a reference to rendered elements. For example, we can get a reference to a <canvas> element:
<canvas
bind:this={canvas}
width={32}
height={32}
></canvas>
Note that the value of canvas will be undefined until the component has mounted, so we put the logic inside the onMount life cycle function. You can check complete interactive example here.
Component Bindings
Just as you can bind to properties of DOM elements, you can bind to component props. For example, we can bind to the value prop of this <Keypad> custom component as though it were a form element:
<Keypad bind:value={pin} on:submit={handleSubmit}/>
Now, when the user interacts with the keypad, the value of pin in the parent component is immediately updated. Check complete example of app to enter pin number and alert the result here.
Don't forget to update keypad component with bind:value={pin} to see the correct result.
Use component bindings sparingly. It can be difficult to track the flow of data around your application if you have too many of them, especially if there is no 'single source of truth'.