1. Template Syntax
  2. Element Directives

Template Syntax

Element Directives

As well as attributes, elements can have directives, which control the element's behaviour in some way.

on:_eventname_

        on:eventname={handler}

      
        on:eventname|modifiers={handler}

      

Use the on: directive to listen to DOM events.

        <script>
	let count = 0;

	function handleClick(event) {
		count += 1;
	}
</script>

<button on:click={handleClick}>
	count: {count}
</button>

      

Handlers can be declared inline with no performance penalty. As with attributes, directive values may be quoted for the sake of syntax highlighters.

        <button on:click="{() => count += 1}">
	count: {count}
</button>

      

Add modifiers to DOM events with the | character.

        <form on:submit|preventDefault={handleSubmit}>
	<!-- the `submit` event's default is prevented,
	     so the page won't reload -->
</form>

      

The following modifiers are available:

  • preventDefault — calls event.preventDefault() before running the handler
  • stopPropagation — calls event.stopPropagation(), preventing the event reaching the next element
  • passive — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
  • nonpassive — explicitly set passive: false
  • capture — fires the handler during the capture phase instead of the bubbling phase
  • once — remove the handler after the first time it runs
  • self — only trigger handler if event.target is the element itself
  • trusted — only trigger handler if event.isTrusted is true. I.e. if the event is triggered by a user action.

Modifiers can be chained together, e.g. on:click|once|capture={...}.

If the on: directive is used without a value, the component will forward the event, meaning that a consumer of the component can listen for it.

        <button on:click>
	The component itself will emit the click event
</button>

      

It's possible to have multiple event listeners for the same event:

        <script>
	let counter = 0;
	function increment() {
		counter = counter + 1;
	}

	function track(event) {
		trackEvent(event)
	}
</script>

<button on:click={increment} on:click={track}>Click me!</button>

      

bind:_property_

        bind:property={variable}

      

Data ordinarily flows down, from parent to child. The bind: directive allows data to flow the other way, from child to parent. Most bindings are specific to particular elements.

The simplest bindings reflect the value of a property, such as input.value.

        <input bind:value={name}>
<textarea bind:value={text}></textarea>

<input type="checkbox" bind:checked={yes}>

      

If the name matches the value, you can use a shorthand.

        <!-- These are equivalent -->
<input bind:value={value}>
<input bind:value>

      

Numeric input values are coerced; even though input.value is a string as far as the DOM is concerned, Svelte will treat it as a number. If the input is empty or invalid (in the case of type="number"), the value is undefined.

        <input type="number" bind:value={num}>
<input type="range" bind:value={num}>

      

On <input> elements with type="file", you can use bind:files to get the FileList of selected files. It is readonly.

        <label for="avatar">Upload a picture:</label>
<input
	accept="image/png, image/jpeg"
	bind:files
	id="avatar"
	name="avatar"
	type="file"
/>

      

bind: can be used together with on: directives. The order that they are defined in determines the value of the bound variable when the event handler is called.

        <script>
	let value = 'Hello World';
</script>

<input
	on:input="{() => console.log('Old value:', value)}"
	bind:value
	on:input="{() => console.log('New value:', value)}"
/>

      

Select Element Bindings

A <select> value binding corresponds to the value property on the selected <option>, which can be any value (not just strings, as is normally the case in the DOM).

        <select bind:value={selected}>
	<option value={a}>a</option>
	<option value={b}>b</option>
	<option value={c}>c</option>
</select>

      

A <select multiple> element behaves similarly to a checkbox group.

        <select multiple bind:value={fillings}>
	<option value="Rice">Rice</option>
	<option value="Beans">Beans</option>
	<option value="Cheese">Cheese</option>
	<option value="Guac (extra)">Guac (extra)</option>
</select>

      

When the value of an <option> matches its text content, the attribute can be omitted.

        <select multiple bind:value={fillings}>
	<option>Rice</option>
	<option>Beans</option>
	<option>Cheese</option>
	<option>Guac (extra)</option>
</select>

      

Elements with the contenteditable attribute support innerHTML and textContent bindings.

        <div contenteditable="true" bind:innerHTML={html}></div>

      

<details> elements support binding to the open property.

        <details bind:open={isOpen}>
	<summary>Details</summary>
	<p>
		Something small enough to escape casual notice.
	</p>
</details>

      

Media Element Bindings

Media elements (<audio> and <video>) have their own set of bindings — six readonly ones...

  • duration (readonly) — the total duration of the video, in seconds
  • buffered (readonly) — an array of {start, end} objects
  • played (readonly) — ditto
  • seekable (readonly) — ditto
  • seeking (readonly) — boolean
  • ended (readonly) — boolean

...and five two-way bindings:

  • currentTime — the current playback time in the video, in seconds
  • playbackRate — how fast or slow to play the video, where 1 is 'normal'
  • paused — this one should be self-explanatory
  • volume — a value between 0 and 1
  • muted — a boolean value indicating whether the player is muted

Videos additionally have readonly videoWidth and videoHeight bindings.

        <video
	src={clip}
	bind:duration
	bind:buffered
	bind:played
	bind:seekable
	bind:seeking
	bind:ended
	bind:currentTime
	bind:playbackRate
	bind:paused
	bind:volume
	bind:muted
	bind:videoWidth
	bind:videoHeight
></video>

      

Block Element Bindings

Block-level elements have 4 readonly bindings, measured using a technique similar to this one:

  • clientWidth
  • clientHeight
  • offsetWidth
  • offsetHeight
        <div
	bind:offsetWidth={width}
	bind:offsetHeight={height}
>
	<Chart {width} {height}/>
</div>

      

bind:group

        bind:group={variable}

      

Inputs that work together can use bind:group.

        <script>
	let tortilla = 'Plain';
	let fillings = [];
</script>

<!-- grouped radio inputs are mutually exclusive -->
<input type="radio" bind:group={tortilla} value="Plain">
<input type="radio" bind:group={tortilla} value="Whole wheat">
<input type="radio" bind:group={tortilla} value="Spinach">

<!-- grouped checkbox inputs populate an array -->
<input type="checkbox" bind:group={fillings} value="Rice">
<input type="checkbox" bind:group={fillings} value="Beans">
<input type="checkbox" bind:group={fillings} value="Cheese">
<input type="checkbox" bind:group={fillings} value="Guac (extra)">

      

bind:this

        bind:this={dom_node}

      

To get a reference to a DOM node, use bind:this.

        <script>
	import { onMount } from 'svelte';

	let canvasElement;

	onMount(() => {
		const ctx = canvasElement.getContext('2d');
		drawStuff(ctx);
	});
</script>

<canvas bind:this={canvasElement}></canvas>

      

class:_name_

        class:name={value}

      
        class:name

      

A class: directive provides a shorter way of toggling a class on an element.

        <!-- These are equivalent -->
<div class="{active ? 'active' : ''}">...</div>
<div class:active={active}>...</div>

<!-- Shorthand, for when name and value match -->
<div class:active>...</div>

<!-- Multiple class toggles can be included -->
<div class:active class:inactive={!active} class:isAdmin>...</div>

      

style:_property_

        style:property={value}

      
        style:property="value"

      
        style:property

      

The style: directive provides a shorthand for setting multiple styles on an element.

        <!-- These are equivalent -->
<div style:color="red">...</div>
<div style="color: red;">...</div>

<!-- Variables can be used -->
<div style:color={myColor}>...</div>

<!-- Shorthand, for when property and variable name match -->
<div style:color>...</div>

<!-- Multiple styles can be included -->
<div style:color style:width="12rem" style:background-color={darkMode ? "black" : "white"}>...</div>

      

When style: directives are combined with style attributes, the directives will take precedence:

        <div style="color: blue;" style:color="red">This will be red</div>

      

use:_action_

        use:action

      
        use:action={parameters}

      
        action = (node: HTMLElement, parameters: any) => {
	update?: (parameters: any) => void,
	destroy?: () => void
}

      

Actions are functions that are called when an element is created. They can return an object with a destroy method that is called after the element is unmounted:

        <script>
	function foo(node) {
		// the node has been mounted in the DOM

		return {
			destroy() {
				// the node has been removed from the DOM
			}
		};
	}
</script>

<div use:foo></div>

      

An action can have a parameter. If the returned value has an update method, it will be called whenever that parameter changes, immediately after Svelte has applied updates to the markup.

INFO

Don't worry about the fact that we're redeclaring the foo function for every component instance — Svelte will hoist any functions that don't depend on local state out of the component definition.

        <script>
	export let bar;

	function foo(node, bar) {
		// the node has been mounted in the DOM

		return {
			update(bar) {
				// the value of `bar` has changed
			},

			destroy() {
				// the node has been removed from the DOM
			}
		};
	}
</script>

<div use:foo={bar}></div>

      

transition:_fn_

        transition:fn

      
        transition:fn={params}

      
        transition:fn|local

      
        transition:fn|local={params}

      
        transition = (node: HTMLElement, params: any) => {
	delay?: number,
	duration?: number,
	easing?: (t: number) => number,
	css?: (t: number, u: number) => string,
	tick?: (t: number, u: number) => void
}

      

A transition is triggered by an element entering or leaving the DOM as a result of a state change.

When a block is transitioning out, all elements inside the block, including those that do not have their own transitions, are kept in the DOM until every transition in the block has completed.

The transition: directive indicates a bidirectional transition, which means it can be smoothly reversed while the transition is in progress.

        {#if visible}
	<div transition:fade>
		fades in and out
	</div>
{/if}

      
TIP

By default intro transitions will not play on first render. You can modify this behaviour by setting intro: true when you create a component.

Transition Parameters

Like actions, transitions can have parameters.

(The double {{curlies}} aren't a special syntax; this is an object literal inside an expression tag.)

        {#if visible}
	<div transition:fade="{{ duration: 2000 }}">
		flies in, fades out over two seconds
	</div>
{/if}

      

Custom Transition Functions

Transitions can use custom functions. If the returned object has a css function, Svelte will create a CSS animation that plays on the element.

The t argument passed to css is a value between 0 and 1 after the easing function has been applied. In transitions run from 0 to 1, out transitions run from 1 to 0 — in other words 1 is the element's natural state, as though no transition had been applied. The u argument is equal to 1 - t.

The function is called repeatedly before the transition begins, with different t and u arguments.

        <script>
	import { elasticOut } from 'svelte/easing';

	export let visible;

	function whoosh(node, params) {
		const existingTransform = getComputedStyle(node).transform.replace('none', '');

		return {
			delay: params.delay || 0,
			duration: params.duration || 400,
			easing: params.easing || elasticOut,
			css: (t, u) => `transform: ${existingTransform} scale(${t})`
		};
	}
</script>

{#if visible}
	<div in:whoosh>
		whooshes in
	</div>
{/if}

      

A custom transition function can also return a tick function, which is called during the transition with the same t and u arguments.

TIP

If it's possible to use css instead of tick, do so — CSS animations can run off the main thread, preventing jank on slower devices.

        <script>
	export let visible = false;

	function typewriter(node, { speed = 1 }) {
		const valid = (
			node.childNodes.length === 1 &&
			node.childNodes[0].nodeType === Node.TEXT_NODE
		);

		if (!valid) {
			throw new Error(`This transition only works on elements with a single text node child`);
		}

		const text = node.textContent;
		const duration = text.length / (speed * 0.01);

		return {
			duration,
			tick: t => {
				const i = ~~(text.length * t);
				node.textContent = text.slice(0, i);
			}
		};
	}
</script>

{#if visible}
	<p in:typewriter="{{ speed: 1 }}">
		The quick brown fox jumps over the lazy dog
	</p>
{/if}

      

If a transition returns a function instead of a transition object, the function will be called in the next microtask. This allows multiple transitions to coordinate, making crossfade effects possible.

Transition Events

An element with transitions will dispatch the following events in addition to any standard DOM events:

  • introstart
  • introend
  • outrostart
  • outroend
        {#if visible}
	<p
		transition:fly="{{ y: 200, duration: 2000 }}"
		on:introstart="{() => status = 'intro started'}"
		on:outrostart="{() => status = 'outro started'}"
		on:introend="{() => status = 'intro ended'}"
		on:outroend="{() => status = 'outro ended'}"
	>
		Flies in and out
	</p>
{/if}

      

Local transitions only play when the block they belong to is created or destroyed, not when parent blocks are created or destroyed.

        {#if x}
	{#if y}
		<p transition:fade>
			fades in and out when x or y change
		</p>

		<p transition:fade|local>
			fades in and out only when y changes
		</p>
	{/if}
{/if}

      

in:_fn_/out:_fn_

        in:fn

      
        in:fn={params}

      
        in:fn|local

      
        in:fn|local={params}

      
        out:fn

      
        out:fn={params}

      
        out:fn|local

      
        out:fn|local={params}

      

Similar to transition:, but only applies to elements entering (in:) or leaving (out:) the DOM.

Unlike with transition:, transitions applied with in: and out: are not bidirectional — an in transition will continue to 'play' alongside the out transition, rather than reversing, if the block is outroed while the transition is in progress. If an out transition is aborted, transitions will restart from scratch.

        {#if visible}
	<div in:fly out:fade>
		flies in, fades out
	</div>
{/if}

      

animate:_fn_

        animate:name

      
        animate:name={params}

      
        animation = (node: HTMLElement, { from: DOMRect, to: DOMRect } , params: any) => {
	delay?: number,
	duration?: number,
	easing?: (t: number) => number,
	css?: (t: number, u: number) => string,
	tick?: (t: number, u: number) => void
}

      
        DOMRect {
	bottom: number,
	height: number,
	​​left: number,
	right: number,
top: number,
	width: number,
	x: number,
	y: number
}

      

An animation is triggered when the contents of a keyed each block are re-ordered. Animations do not run when an element is added or removed, only when the index of an existing data item within the each block changes. Animate directives must be on an element that is an immediate child of a keyed each block.

Animations can be used with Svelte's built-in animation functions or custom animation functions.

        <!-- When `list` is reordered the animation will run-->
{#each list as item, index (item)}
	<li animate:flip>{item}</li>
{/each}

      

Animation Parameters

As with actions and transitions, animations can have parameters.

(The double {{curlies}} aren't a special syntax; this is an object literal inside an expression tag.)

        {#each list as item, index (item)}
	<li animate:flip="{{ delay: 500 }}">{item}</li>
{/each}

      

Custom Animation Functions

Animations can use custom functions that provide the node, an animation object and any parameters as arguments. The animation parameter is an object containing from and to properties each containing a DOMRect describing the geometry of the element in its start and end positions. The from property is the DOMRect of the element in its starting position, the to property is the DOMRect of the element in its final position after the list has been reordered and the DOM updated.

If the returned object has a css method, Svelte will create a CSS animation that plays on the element.

The t argument passed to css is a value that goes from 0 and 1 after the easing function has been applied. The u argument is equal to 1 - t.

The function is called repeatedly before the animation begins, with different t and u arguments.

        <script>
	import { cubicOut } from 'svelte/easing';

	function whizz(node, { from, to }, params) {

		const dx = from.left - to.left;
		const dy = from.top - to.top;

		const d = Math.sqrt(dx * dx + dy * dy);

		return {
			delay: 0,
			duration: Math.sqrt(d) * 120,
			easing: cubicOut,
			css: (t, u) =>
				`transform: translate(${u * dx}px, ${u * dy}px) rotate(${t*360}deg);`
		};
	}
</script>

{#each list as item, index (item)}
	<div animate:whizz>{item}</div>
{/each}

      

A custom animation function can also return a tick function, which is called during the animation with the same t and u arguments.

TIP

If it's possible to use css instead of tick, do so — CSS animations can run off the main thread, preventing jank on slower devices.

        <script>
	import { cubicOut } from 'svelte/easing';

	function whizz(node, { from, to }, params) {

		const dx = from.left - to.left;
		const dy = from.top - to.top;

		const d = Math.sqrt(dx * dx + dy * dy);

		return {
		delay: 0,
		duration: Math.sqrt(d) * 120,
		easing: cubicOut,
		tick: (t, u) =>
			Object.assign(node.style, {
				color: t > 0.5 ? 'Pink' : 'Blue'
			});
	};
	}
</script>

{#each list as item, index (item)}
	<div animate:whizz>{item}</div>
{/each}