Menu

Introduction edit this section

What is Svelte?

Svelte is a tool for building fast web applications.

It is similar to JavaScript frameworks such as React, Angular, Vue, and Ractive, which all share a goal of making it easy to build slick interactive user interfaces.

But there's a crucial difference: Svelte converts your app into ideal JavaScript at build time, rather than interpreting your application code at run time. This means you don't pay the performance cost of the framework's abstractions, and you don't incur a penalty when your app first loads.

You can build your entire app with Svelte, or you can add it incrementally to an existing codebase. You can also ship components as standalone packages that work anywhere, without the overhead of a dependency on a conventional framework.

Read the introductory blog post to learn more about Svelte's goals and philosophy.

Understanding Svelte components

In Svelte, an application is composed from one or more components. A component is a reusable self-contained block of code that encapsulates markup, styles and behaviours that belong together.

Like Ractive and Vue, Svelte promotes the concept of single-file components: a component is just an .html file. Here's a simple example:

REPL App.html
<h1>Hello {name}!</h1>

Wherever you see REPL links, click through for an interactive example

Svelte turns this into a JavaScript module that you can import into your app:

main.js
import App from './App.html';

const app = new App({
	target: document.querySelector('main'),
	data: { name: 'world' }
});

// change the data associated with the template
app.set({ name: 'everybody' });

// detach the component and clean everything up
app.destroy();

Congratulations, you've just learned about half of Svelte's API!

Getting started

Normally, this is the part where the instructions might tell you to add the framework to your page as a <script> tag. But because Svelte runs at build time, it works a little bit differently.

The best way to use Svelte is to integrate it into your build system – there are plugins for Rollup, Browserify, Gulp and others, with more on the way. See here for an up-to-date list.

You will need to have Node.js installed, and have some familiarity with the command line

Getting started using the REPL

Going to the REPL and pressing the download button on any of the examples will give you a .zip file containing everything you need to run that example locally. Just unzip it, cd to the directory, and run npm install and npm run dev. See this blog post for more information.

Getting started using degit

degit is a tool for creating projects from templates stored in git repos. Install it globally...

npm install -g degit

...then you can use it to spin up a new project:

degit sveltejs/template my-new-project
cd my-new-project
npm install
npm run dev

You can use any git repo you like — these are the 'official' templates:

Getting started using the CLI

Svelte also provides a Command Line Interface, but it's not recommended for production use. The CLI will compile your components to standalone JavaScript files, but won't automatically recompile them when they change, and won't deduplicate code shared between your components. Use one of the above methods instead.

If you've installed svelte globally, you can use svelte --help for a complete list of options. Some examples of the more common operations are:

# Generate a JavaScript module from MyComponent.html
svelte compile MyComponent.html > MyComponent.js
svelte compile -i MyComponent.html -o MyComponent.js

# Generate a UMD module from MyComponent.html, inferring its name from the filename ('MyComponent')
svelte compile -f umd MyComponent.html > MyComponent.js

# Generate a UMD module, specifying the name
svelte compile -f umd -n CustomName MyComponent.html > MyComponent.js

# Compile all .html files in a directory
svelte compile -i src/components -o build/components

You can also use npx to use the CLI without installing Svelte globally — just prefix your command with npx: npx svelte compile ...

Component API edit this section

As we saw above, you create a component instance with the new keyword:

main.js
import MyComponent from './MyComponent.html';

const component = new MyComponent({
	// `target` is the only required option – the element
	// to render the component to
	target: document.querySelector('main'),

	// `data` is optional. A component can also have
	// default data – we'll learn about that later.
	data: {
		questions: [
			'life',
			'the universe',
			'everything'
		],
		answer: 42
	}
});

Every Svelte component instance has a small number of methods you can use to control it, in addition to any custom methods you add.

component.set(state)

This updates the component's state with the new values provided and causes the DOM to update. state must be a plain old JavaScript object (POJO). Any properties not included in state will remain as they were.

component.set({
	questions: [
		'why is the sky blue?',
		'how do planes fly?',
		'where do babies come from?'
	],
	answer: 'ask your mother'
});

component.get()

Returns the component's current state:

const { questions, answer } = component.get();
console.log(answer); // 'ask your mother'

This will also retrieve the value of computed properties.

Previous versions of Svelte allowed you to specify a key to retrieve a specific value — this was removed in version 2.

component.on(eventName, callback)

Allows you to respond to events:

const listener = component.on('thingHappened', event => {
	console.log(`A thing happened: ${event.thing}`);
});

// some time later...
listener.cancel();

Each component has three built-in events, corresponding to their lifecycle hooks:

component.on('state', ({ changed, current, previous }) => {
	console.log('state changed', current);
});

component.on('update', ({ changed, current, previous }) => {
	console.log('DOM updated after state change', current);
});

component.on('destroy', () => {
	console.log('this component is being destroyed');
});

component.fire(eventName, event)

The companion to component.on(...):

component.fire('thingHappened', {
	thing: 'this event was fired'
});

At first glance component.on(...) and component.fire(...) aren't particularly useful, but it'll become more so when we learn about nested components and component events.

component.destroy()

Removes the component from the DOM and removes any event listeners that were created. This will also fire a destroy event:

component.on('destroy', () => {
	alert('goodbye!'); // please don't do this
});

component.destroy();

component.options

The options used to instantiate the component are available in component.options.

REPL App.html
Check the console.

<script>
	export default {
		oncreate() {
			console.log(this.options);
		}
	};
</script>

This gives you access to standard options like target and data, but can also be used to access any other custom options you may choose to implement for your component.

component.root

In nested components, each component has a root property pointing to the top-level root component – that is, the one instantiated with new MyComponent({...}).

Earlier versions of Svelte had a component.observe(...) method. This was removed in version 2, in favour of the onstate lifecycle hook, but is still available via svelte-extras.

Template syntax edit this section

Rather than reinventing the wheel, Svelte templates are built on foundations that have stood the test of time: HTML, CSS and JavaScript. There's very little extra stuff to learn.

Svelte version 1 had a slightly different template syntax. You can upgrade older components automatically using svelte-upgrade.

Tags

Tags allow you to bind data to your template. Whenever your data changes (for example after component.set(...)), the DOM updates automatically. You can use any JavaScript expression in templates, and it will also automatically update:

REPL App.html
<p>{a} + {b} = {a + b}</p>

You can also use tags in attributes:

REPL App.html
<h1 style="color: {color};">{color}</h1>
<p hidden={hideParagraph}>You can hide this paragraph.</p>

Boolean attributes like hidden will be omitted if the tag expression evaluates to false.

HTML

Ordinary tags render expressions as plain text. If you need your expression interpreted as HTML, wrap it in a special @html tag:

REPL App.html
<p>This HTML: {content}</p>
<p>Renders as: {@html content}</p>

As with regular tags, you can use any JavaScript expression in HTML tags, and it will automatically update the document when your data changes.

HTML is not sanitized before it is rendered! If you are displaying user input, you are responsible for first sanitizing it. Not doing so potentially opens you up to XSS attacks.

If blocks

Control whether or not part of your template is rendered by wrapping it in an if block.

App.html
{#if user.loggedIn}
	<a href="/logout">log out</a>
{/if}

{#if !user.loggedIn}
	<a href="/login">log in</a>
{/if}

You can combine the two blocks above with {:else}:

App.html
{#if user.loggedIn}
	<a href="/logout">log out</a>
{:else}
	<a href="/login">log in</a>
{/if}

You can also use {:elseif ...}:

REPL App.html
{#if x > 10}
	<p>{x} is greater than 10</p>
{:elseif 5 > x}
	<p>{x} is less than 5</p>
{:else}
	<p>{x} is between 5 and 10</p>
{/if}

Each blocks

Iterate over lists of data:

REPL App.html
<h1>Cats of YouTube</h1>

<ul>
	{#each cats as cat}
		<li><a target="_blank" href={cat.video}>{cat.name}</a></li>
	{:else}
		<li>No cats :(</li>
	{/each}
</ul>

Else is triggered when the list is empty.

You can access the index of the current element with expression as name, index:

REPL App.html
<div class="grid">
	{#each rows as row, y}
		<div class="row">
			{#each columns as column, x}
				<code class="cell">
					{x + 1},{y + 1}:
					<strong>{row[column]}</strong>
				</code>
			{/each}
		</div>
	{/each}
</div>

By default, if the list a, b, c becomes a, c, Svelte will remove the third block and change the second from b to c, rather than removing b. If that's not what you want, use a keyed each block.

You can use destructuring patterns on the elements of the array:

REPL App.html
<h1>It's the cats of YouTube again</h1>

<ul>
	{#each cats as {name, video} }
		<li><a target="_blank" href={video}>{name}</a></li>
	{/each}
</ul>

If you want to iterate over an object you can use Object.entries(object) which returns the object's properties as [key, value] pairs:

REPL App.html
<h1>Cats and Dogs</h1>

{#each Object.entries(animals) as [animal, names]}
	<p>{animal}: {names.join(" and ")}</p>
{/each}

Await blocks

You can represent the three states of a Promise — pending, fulfilled and rejected — with an await block:

REPL App.html
{#await promise}
	<p>wait for it...</p>
{:then answer}
	<p>the answer is {answer}!</p>
{:catch error}
	<p>well that's odd</p>
{/await}

<script>
	export default {
		data() {
			return {
				promise: new Promise(fulfil => {
					setTimeout(() => fulfil(42), 3000);
				})
			};
		}
	};
</script>

If the expression in {#await expression} isn't a promise, Svelte skips ahead to the then section.

Directives

Directives allow you to add special instructions for adding event handlers, bindings, referencing elements and so on. We'll cover each of those in later stages of this guide – for now, all you need to know is that directives can be identified by the : character:

REPL App.html
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>

Technically, the : character is used to denote namespaced attributes in HTML. These will not be treated as directives, if encountered.

Debug tags

To inspect data as it changes and flows through your app, use a {@debug ...} tag:

REPL App.html
<input bind:value=name>

{@debug name}
<h1>Hello {name}!</h1>

This will log the value of name whenever it changes. If your devtools are open, changing name will pause execution and open the debugger.

You can debug multiple values simultaneously ({@debug foo, bar, baz}), or use {@debug} to pause execution whenever the surrounding markup is updated.

Debug tags only have an effect when compiling with the dev: true compiler option.

Scoped styles edit this section

One of Svelte's key tenets is that components should be self-contained and reusable in different contexts. Because of that, it has a mechanism for scoping your CSS, so that you don't accidentally clobber other selectors on the page.

Adding styles

Your component template can have a <style> tag, like so:

REPL App.html
<div class="foo">
	Big red Comic Sans
</div>

<style>
	.foo {
		color: red;
		font-size: 2em;
		font-family: 'Comic Sans MS';
	}
</style>

How it works

Open the example above in the REPL and inspect the element to see what has happened – Svelte has added a svelte-[uniqueid] class to the element, and transformed the CSS selector accordingly. Since no other element on the page can share that selector, anything else on the page with class="foo" will be unaffected by our styles.

This is vastly simpler than achieving the same effect via Shadow DOM and works everywhere without polyfills.

Svelte will add a <style> tag to the page containing your scoped styles. Dynamically adding styles may be impossible if your site has a Content Security Policy. If that's the case, you can use scoped styles by server-rendering your CSS and using the css: false compiler option (or --no-css with the CLI).

Cascading rules

Styles will only apply to the current component, unless you opt in to cascading with the :global(...) modifier:

App.html
<div>
	<Widget/>
</div>

<style>
	p {
		/* this block will be disregarded, since
		   there are no <p> elements here */
		color: red;
	}

	div :global(p) {
		/* this block will be applied to any <p> elements
		   inside the <div>, i.e. in <Widget> */
		font-weight: bold;
	}
</style>

<script>
	import Widget from './Widget.html';

	export default {
		components: { Widget }
	};
</script>

Scoped styles are not dynamic – they are shared between all instances of a component. In other words you can't use {tags} inside your CSS.

Unused style removal

Svelte will identify and remove any styles that it can guarantee are not being used in your app. It will also emit a warning so that you can remove them from the source.

Special selectors

If you have a ref on an element, you can use it as a CSS selector. The ref:* selector has the same specificity as a class or attribute selector.

REPL App.html
<div ref:foo>
	yeah!
</div>

<style>
	ref:foo {
		color: magenta;
		font-size: 5em;
	}
</style>

Behaviours edit this section

As well as scoped styles and a template, components can encapsulate behaviours. For that, we add a <script> element and export an object:

REPL App.html
<div>
	<!-- template goes here -->
</div>

<script>
	export default {
		// behaviours go here
	};
</script>

Default data

Often, it makes sense for a component to have default data. This should be expressed as a function that returns a plain JavaScript object:

REPL App.html
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>

<script>
	export default {
		data() {
			return {
				count: 0
			};
		}
	};
</script>

Data supplied at instantiation takes priority over defaults. In other words, if we instantiated the component above like so...

const counter = new Counter({
	data: {
		count: 99
	}
});

...then {count}, or counter.get().count, would initially be 99 rather than 0.

Computed properties

Often, your program will use values that depend on other values – for example, you might have a filtered list, which depends on both the list and the filter. Normally in JavaScript you'd have to add logic to update the dependent property when any of the dependencies change. This is a frequent source of bugs, and it gets worse as your application grows.

Svelte allows you to express these dependencies in computed properties, which are recalculated whenever those dependencies change:

REPL App.html
<p>
	The time is
	<strong>{hours}:{minutes}:{seconds}</strong>
</p>

<script>
	export default {
		data() {
			return {
				time: new Date()
			};
		},

		computed: {
			hours:   ({ time }) => time.getHours(),
			minutes: ({ time }) => time.getMinutes(),
			seconds: ({ time }) => time.getSeconds()
		}
	};
</script>

Each function is passed the component's current state object. Because we're using destructuring syntax, the compiler knows that hours, minutes and seconds only need to re-run when time changes, and not when any other values change. There's no costly dependency tracking involved – the dependency graph is resolved at compile time.

computed must be an object literal, and the properties must be function expressions or arrow function expressions. Any external functions used in computed must be wrapped here:

import externalFunc from '_external_file';
export default {
	computed: {
		externalFunc: ({ dep1, dep2 }) => externalFunc(dep1, dep2);
	}
}

Computed properties can of course return functions. For example, we could dynamically generate a filter function for a list of items:

REPL App.html
<input bind:value=search>

{#each items.filter(predicate) as word}
	<p><strong>{word.slice(0, search.length)}</strong>{word.slice(search.length)}</p>
{:else}
	<p>no matches!</p>
{/each}

<script>
	export default {
		computed: {
			predicate: ({ search }) => {
				search = search.toLowerCase();
				return word => word.startsWith(search);
			}
		}
	};
</script>

Lifecycle hooks

There are four 'hooks' provided by Svelte for adding control logic — oncreate, ondestroy, onstate and onupdate:

REPL App.html
<p>
	The time is
	<strong>{hours}:{minutes}:{seconds}</strong>
</p>

<script>
	export default {
		onstate({ changed, current, previous }) {
			// this fires before oncreate, and on every state change.
			// the first time it runs, `previous` is undefined
			if (changed.time) {
				console.log(`time changed: ${previous && previous.time} -> ${current.time}`);
			}
		},

		oncreate() {
			// this fires when the component has been
			// rendered to the DOM
			console.log('in oncreate');

			this.interval = setInterval(() => {
				this.set({ time: new Date() });
			}, 1000);
		},

		onupdate({ changed, current, previous }) {
			// this fires after oncreate, and after every state change
			// once the DOM is synchronised with the data
			console.log(`The DOM has been updated`);
		},

		ondestroy() {
			// this fires when the component is
			// removed from the DOM
			console.log('in ondestroy');

			clearInterval(this.interval);
		},

		data() {
			return {
				time: new Date()
			};
		},

		computed: {
			hours:   ({ time }) => time.getHours(),
			minutes: ({ time }) => time.getMinutes(),
			seconds: ({ time }) => time.getSeconds()
		}
	};
</script>

You can add event listeners corresponding to onstate, onupdate and ondestroy programmatically — see component.on

Helpers

Helpers are simple functions that are used in your template. In the example above, we want to ensure that minutes and seconds are preceded with a 0 if they only have one digit, so we add a leftPad helper:

REPL App.html
<p>
	The time is
	<strong>{hours}:{leftPad(minutes, 2, '0')}:{leftPad(seconds, 2, '0')}</strong>
</p>

<script>
	import leftPad from 'left-pad';

	export default {
		helpers: {
			leftPad
		},

		oncreate() {
			this.interval = setInterval(() => {
				this.set({ time: new Date() });
			}, 1000);
		},

		ondestroy() {
			clearInterval(this.interval);
		},

		data() {
			return {
				time: new Date()
			};
		},

		computed: {
			hours:   ({ time }) => time.getHours(),
			minutes: ({ time }) => time.getMinutes(),
			seconds: ({ time }) => time.getSeconds()
		}
	};
</script>

Of course, you could use leftPad inside the computed properties instead of in the template. There's no hard and fast rule about when you should use expressions with helpers versus when you should use computed properties – do whatever makes your component easier for the next developer to understand.

Helper functions should be pure – in other words, they should not have side-effects, and their returned value should only depend on their arguments.

Custom methods

In addition to the built-in methods, you can add methods of your own:

REPL App.html
<p>Try calling <code>app.say('hello!')</code> from the console</p>

<script>
	export default {
		methods: {
			say(message) {
				alert(message); // again, please don't do this
			}
		}
	};
</script>

These become part of the component's API:

import MyComponent from './MyComponent.html';

var component = new MyComponent({
	target: document.querySelector('main')
});

component.say('👋');

Methods (whether built-in or custom) can also be called inside event handlers:

App.html
<button on:click="say('hello')">say hello!</button>

Custom event handlers

Soon, we'll learn about event handlers – if you want, skip ahead to that section first then come back here!

Most of the time you can make do with the standard DOM events (the sort you'd add via element.addEventListener, such as click) but sometimes you might need custom events to handle gestures, for example.

Custom events are just functions that take a node and a callback as their argument, and return an object with a destroy method that gets called when the element is removed from the page:

REPL App.html
<button on:longpress="set({ done: true })">click and hold</button>

{#if done}
	<p>clicked and held</p>
{/if}

<script>
	export default {
		events: {
			longpress(node, callback) {
				function onmousedown(event) {
					const timeout = setTimeout(() => callback(event), 1000);

					function cancel() {
						clearTimeout(timeout);
						node.removeEventListener('mouseup', cancel, false);
					}

					node.addEventListener('mouseup', cancel, false);
				}

				node.addEventListener('mousedown', onmousedown, false);

				return {
					destroy() {
						node.removeEventListener('mousedown', onmousedown, false);
					}
				};
			}
		}
	};
</script>

Namespaces

Components are assumed to be in the HTML namespace. If your component is designed to be used inside an <svg> element, you need to specify the namespace:

REPL App.html
<svg viewBox="0 0 1000 1000" style="width: 100%; height: 100%;">
	<SmileyFace x=70 y=280 size=100 fill="#f4d9c7"/>
	<SmileyFace x=800 y=250 size=150 fill="#40250f"/>
	<SmileyFace x=150 y=700 size=110 fill="#d2aa7a"/>
	<SmileyFace x=875 y=730 size=130 fill="#824e2e"/>
	<SmileyFace x=450 y=500 size=240 fill="#d2b198"/>
</svg>

<script>
	import SmileyFace from './SmileyFace.html';

	export default {
		components: { SmileyFace }
	};
</script>
SmileyFace.html
<!-- CC-BY-SA — https://commons.wikimedia.org/wiki/File:718smiley.svg -->
<g transform="translate({x},{y}) scale({size / 366.5})">
	<circle r=366.5/>
	<circle r=336.5 fill={fill}/>
	<path d="m-41.5 298.5c-121-21-194-115-212-233v-8l-25-1-1-18h481c6 13 10 27 13 41 13 94-38 146-114 193-45 23-93 29-142 26z"/>
	<path d="m5.5 280.5c52-6 98-28 138-62 28-25 46-56 51-87 4-20 1-57-5-70l-423-1c-2 56 39 118 74 157 31 34 72 54 116 63 11 2 38 2 49 0z" fill="#871945"/>
	<path d="m-290.5 -24.5c-13-26-13-57-9-85 6-27 18-52 35-68 21-20 50-23 77-18 15 4 28 12 39 23 18 17 30 40 36 67 4 20 4 41 0 60l-6 21z"/>
	<path d="m-132.5 -43.5c5-6 6-40 2-58-3-16-4-16-10-10-14 14-38 14-52 0-15-18-12-41 6-55 3-3 5-5 5-6-1-4-22-8-34-7-42 4-57.6 40-66.2 77-3 17-1 53 4 59h145.2z" fill="#fff"/>
	<path d="m11.5 -23.5c-2-3-6-20-7-29-5-28-1-57 11-83 15-30 41-52 72-60 29-7 57 0 82 15 26 17 45 49 50 82 2 12 2 33 0 45-1 10-5 26-8 30z"/>
	<path d="m198.5 -42.5c4-5 5-34 4-50-2-14-6-24-8-24-1 0-3 2-6 5-17 17-47 13-58-9-7-16-4-31 8-43 4-4 7-8 7-9 0 0-4-2-8-3-51-17-105 20-115 80-3 15 0 43 3 53z" fill="#fff"/>
	<path d="m137.5 223.5s-46 40-105 53c-66 15-114-7-114-7s14-76 93-95c76-18 126 49 126 49z" fill="#f9bedd"/>
</g>

<script>
	export default {
		// you can either use the shorthand 'svg', or the full
		// namespace: 'http://www.w3.org/2000/svg'. (I know
		// which one I prefer.)
		namespace: 'svg',

		data() {
			return {
				x: 100,
				y: 100,
				size: 100
			};
		}
	};
</script>

Nested components edit this section

As well as containing elements (and if blocks and each blocks), Svelte components can contain other Svelte components.

REPL App.html
<div class='widget-container'>
	<Widget/>
</div>

<script>
	import Widget from './Widget.html';

	export default {
		components: {
			Widget
		}
	};
</script>
Widget.html
<p>I am a nested component</p>

That's similar to doing this...

import Widget from './Widget.html';

const widget = new Widget({
	target: document.querySelector('.widget-container')
});

...except that Svelte takes care of destroying the child component when the parent is destroyed, and keeps the two components in sync with props.

Component names must be capitalised, following the widely-used JavaScript convention of capitalising constructor names. It's also an easy way to distinguish components from elements in your template.

Props

Props, short for 'properties', are the means by which you pass data down from a parent to a child component — in other words, they're just like attributes on an element:

REPL App.html
<div class='widget-container'>
	<Widget foo bar="static" baz={dynamic}/>
</div>

<script>
	import Widget from './Widget.html';

	export default {
		components: {
			Widget
		}
	};
</script>
Widget.html
<p>foo: {foo}</p>
<p>bar: {bar}</p>
<p>baz: {baz}</p>

As with element attributes, prop values can contain any valid JavaScript expression.

Often, the name of the property will be the same as the value, in which case we can use a shorthand:

App.html
<!-- these are equivalent -->
<Widget foo={foo}/>
<Widget {foo}/>

Note that props are one-way — to get data from a child component into a parent component, use bindings.

Composing with <slot>

A component can contain a <slot></slot> element, which allows the parent component to inject content:

REPL App.html
<Box>
	<h2>Hello!</h2>
	<p>This is a box. It can contain anything.</p>
</Box>

<script>
	import Box from './Box.html';

	export default {
		components: { Box }
	};
</script>
Box.html
<div class="box">
	<slot><!-- content is injected here --></slot>
</div>

<style>
	.box {
		border: 2px solid black;
		padding: 0.5em;
	}
</style>

The <slot> element can contain 'fallback content', which will be used if no children are provided for the component:

REPL App.html
<Box></Box>

<script>
	import Box from './Box.html';

	export default {
		components: { Box }
	};
</script>
Box.html
<div class="box">
	<slot>
		<p class="fallback">the box is empty!</p>
	</slot>
</div>

<style>
	.box {
		border: 2px solid black;
		padding: 0.5em;
	}

	.fallback {
		color: #999;
	}
</style>

You can also have named slots. Any elements with a corresponding slot attribute will fill these slots:

REPL App.html
<ContactCard>
	<span slot="name">P. Sherman</span>
	<span slot="address">42 Wallaby Way, Sydney</span>
</ContactCard>

<script>
	import ContactCard from './ContactCard.html';

	export default {
		components: { ContactCard }
	};
</script>
ContactCard.html
<div class="contact-card">
	<h2><slot name="name"></slot></h2>
	<slot name="address">Unknown address</slot>
	<br>
	<slot name="email">Unknown email</slot>
</div>

<style>
	.contact-card {
		border: 2px solid black;
		padding: 0.5em;
	}
</style>

Shorthand imports

As an alternative to using an import declaration...

App.html
<script>
	import Widget from './Widget.html';

	export default {
		components: { Widget }
	};
</script>

...you can write this:

App.html
<script>
	export default {
		components: {
			Widget: './Widget.html'
		}
	};
</script>

Special elements edit this section

Svelte includes a handful of built-in elements with special behaviour.

<svelte:self>

Sometimes, a component needs to embed itself recursively — for example if you have a tree-like data structure. In Svelte, that's accomplished with the <svelte:self> tag:

REPL App.html
{#if countdown > 0}
	<p>{countdown}</p>
	<svelte:self countdown="{countdown - 1}"/>
{:else}
	<p>liftoff!</p>
{/if}

<svelte:component>

If you don't know what kind of component to render until the app runs — in other words, it's driven by state — you can use <svelte:component>:

REPL App.html
<input type=checkbox bind:checked=foo> foo
<svelte:component this="{foo ? Red : Blue}" name="thing"/>

<script>
	import Red from './Red.html';
	import Blue from './Blue.html';

	export default {
		data() {
			return { Red, Blue }
		}
	};
</script>

Note that Red and Blue are items in data, not components, unlike if we were doing <Red> or <Blue>.

The expression inside the this="{...}" can be any valid JavaScript expression. For example, it could be a computed property:

REPL App.html
<label><input type=radio bind:group=size value=small> small</label>
<label><input type=radio bind:group=size value=medium> medium</label>
<label><input type=radio bind:group=size value=large> large</label>

<svelte:component this={Size}/>

<script>
	import Small from './Small.html';
	import Medium from './Medium.html';
	import Large from './Large.html';

	export default {
		computed: {
			Size: ({size}) => {
				if (size === 'small') return Small;
				if (size === 'medium') return Medium;
				return Large;
			}
		}
	};
</script>
Small.html
<p style="font-size: 12px">small</p>
Medium.html
<p style="font-size: 18px">medium</p>
Large.html
<p style="font-size: 32px">LARGE</p>

<svelte:window>

The <svelte:window> tag gives you a convenient way to declaratively add event listeners to window. Event listeners are automatically removed when the component is destroyed.

REPL App.html
<svelte:window on:keydown="set({ key: event.key, keyCode: event.keyCode })"/>

{#if key}
	<p><kbd>{key === ' ' ? 'Space' : key}</kbd> (code {keyCode})</p>
{:else}
	<p>click in this window and press any key</p>
{/if}

<style>
	kbd {
		background-color: #eee;
		border: 2px solid #f4f4f4;
		border-right-color: #ddd;
		border-bottom-color: #ddd;
		font-size: 2em;
		margin: 0 0.5em 0 0;
		padding: 0.5em 0.8em;
		font-family: Inconsolata;
	}
</style>

You can also bind to certain values — so far innerWidth, outerWidth, innerHeight, outerHeight, scrollX, scrollY and online:

REPL App.html
<svelte:window bind:scrollY=y/>

<div class="background"></div>
<p class="fixed">user has scrolled {y} pixels</p>

<style>
	.background {
		position: absolute;
		left: 0;
		top: 0;
		width: 100%;
		height: 9999px;
		background: linear-gradient(to bottom, #7db9e8 0%,#0a1d33 100%);
	}

	.fixed {
		position: fixed;
		top: 1em;
		left: 1em;
		color: white;
	}
</style>

<svelte:head>

If you're building an application with Svelte — particularly if you're using Sapper — then it's likely you'll need to add some content to the <head> of your page, such as adding a <title> element.

You can do that with the <svelte:head> tag:

REPL App.html
<svelte:head>
	<title>{post.title} • My blog</title>
</svelte:head>

When server rendering, the <head> contents can be extracted separately to the rest of the markup.

Directives edit this section

Directives are element or component-level instructions to Svelte. They look like attributes, except with a : character.

Event handlers

In most applications, you'll need to respond to the user's actions. In Svelte, this is done with the on:[event] directive.

REPL App.html
<p>Count: {count}</p>
<button on:click="set({ count: count + 1 })">+1</button>

When the user clicks the button, Svelte calls component.set(...) with the provided arguments. You can call any method belonging to the component (whether built-in or custom), and any data property (or computed property) that's in scope:

REPL App.html
<p>Select a category:</p>

{#each categories as category}
	<button on:click="select(category)">select {category}</button>
{/each}

<script>
	export default {
		data() {
			return {
				categories: [
					'animal',
					'vegetable',
					'mineral'
				]
			}
		},

		methods: {
			select(name) {
				alert(`selected ${name}`); // seriously, please don't do this
			}
		}
	};
</script>

You can also access the event object in the method call:

REPL App.html
<div on:mousemove="set({ x: event.clientX, y: event.clientY })">
	coords: {x},{y}
</div>

<style>
	div {
		border: 1px solid purple;
		width: 100%;
		height: 100%;
	}
</style>

The target node can be referenced as this, meaning you can do this sort of thing:

REPL App.html
<input on:focus="this.select()" value="click to select">

Custom events

You can define your own custom events to handle complex user interactions like dragging and swiping. See the earlier section on custom event handlers for more information.

Component events

Events are an excellent way for nested components to communicate with their parents. Let's revisit our earlier example, but turn it into a <CategoryChooser> component:

CategoryChooser.html
<p>Select a category:</p>

{#each categories as category}
	<button on:click="fire('select', { category })">select {category}</button>
{/each}

<script>
	export default {
		data() {
			return {
				categories: [
					'animal',
					'vegetable',
					'mineral'
				]
			}
		}
	};
</script>

When the user clicks a button, the component will fire a select event, where the event object has a category property. Any component that nests <CategoryChooser> can listen for events like so:

REPL App.html
<CategoryChooser on:select="playTwentyQuestions(event.category)"/>

<script>
	import CategoryChooser from './CategoryChooser.html';

	export default {
		components: {
			CategoryChooser
		},

		methods: {
			playTwentyQuestions(category) {
				alert(`ok! you chose ${category}`);
			}
		}
	};
</script>

Just as this in an element's event handler refers to the element itself, in a component event handler this refers to the component firing the event.

There is also a shorthand for listening for and re-firing an event unchanged.

App.html
<!-- these are equivalent -->
<Widget on:foo="fire('foo', event)"/>
<Widget on:foo/>

Since component events do not propagate as DOM events do, this can be used to pass events through intermediate components. This shorthand technique also applies to element events (on:click is equivalent to on:click="fire('click', event)").

Refs

Refs are a convenient way to store a reference to particular DOM nodes or components. Declare a ref with ref:[name], and access it inside your component's methods with this.refs.[name]:

REPL App.html
<canvas ref:canvas width=200 height=200></canvas>

<script>
	import createRenderer from './createRenderer.js';

	export default {
		oncreate() {
			const canvas = this.refs.canvas;
			const ctx = canvas.getContext('2d');

			const renderer = createRenderer(canvas, ctx);
			this.on('destroy', renderer.stop);
		}
	}
</script>

Since only one element or component can occupy a given ref, don't use them in {#each ...} blocks. It's fine to use them in {#if ...} blocks however.

Note that you can use refs in your <style> blocks — see Special selectors.

Transitions

Transitions allow elements to enter and leave the DOM gracefully, rather than suddenly appearing and disappearing.

REPL App.html
<input type=checkbox bind:checked=visible> visible

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

<script>
	import { fade } from 'svelte-transitions';

	export default {
		transitions: { fade }
	};
</script>

Transitions can have parameters — typically delay and duration, but often others, depending on the transition in question. For example, here's the fly transition from the svelte-transitions package:

REPL App.html
<input type=checkbox bind:checked=visible> visible

{#if visible}
	<p transition:fly="{y: 200, duration: 1000}">flies 200 pixels up, slowly</p>
{/if}

<script>
	import { fly } from 'svelte-transitions';

	export default {
		transitions: { fly }
	};
</script>

An element can have separate in and out transitions:

REPL App.html
<input type=checkbox bind:checked=visible> visible

{#if visible}
	<p in:fly="{y: 50}" out:fade>flies up, fades out</p>
{/if}

<script>
	import { fade, fly } from 'svelte-transitions';

	export default {
		transitions: { fade, fly }
	};
</script>

Transitions are simple functions that take a node and any provided parameters and return an object with the following properties:

  • duration — how long the transition takes in milliseconds
  • delay — milliseconds before the transition starts
  • easing — an easing function
  • css — a function that accepts an argument t between 0 and 1 and returns the styles that should be applied at that moment
  • tick — a function that will be called on every frame, with the same t argument, while the transition is in progress

Of these, duration is required, as is either css or tick. The rest are optional. Here's how the fade transition is implemented, for example:

REPL App.html
<input type=checkbox bind:checked=visible> visible

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

<script>
	export default {
		transitions: {
			fade(node, { delay = 0, duration = 400 }) {
				const o = +getComputedStyle(node).opacity;

				return {
					delay,
					duration,
					css: t => `opacity: ${t * o}`
				};
			}
		}
	};
</script>

If the css option is used, Svelte will create a CSS animation that runs efficiently off the main thread. Therefore if you can achieve an effect using css rather than tick, you should.

Bindings

As we've seen, data can be passed down to elements and components with attributes and props. Occasionally, you need to get data back up; for that we use bindings.

Component bindings

Component bindings keep values in sync between a parent and a child:

App.html
<Widget bind:childValue=parentValue/>

Whenever childValue changes in the child component, parentValue will be updated in the parent component and vice versa.

If the names are the same, you can shorten the declaration:

App.html
<Widget bind:value/>

Use component bindings judiciously. They can save you a lot of boilerplate, but will make it harder to reason about data flow within your application if you overuse them.

Element bindings

Element bindings make it easy to respond to user interactions:

REPL App.html
<h1>Hello {name}!</h1>
<input bind:value=name>

Some bindings are one-way, meaning that the values are read-only. Most are two-way — changing the data programmatically will update the DOM. The following bindings are available:

Name Applies to Kind
value <input> <textarea> <select> Two-way
checked <input type=checkbox> Two-way
group (see note) <input type=checkbox> <input type=radio> Two-way
currentTime paused played volume <audio> <video> Two-way
buffered duration seekable <audio> <video> One-way
offsetWidth offsetHeight clientWidth clientHeight All block-level elements One-way
scrollX scrollY <svelte:window> Two-way
online innerWidth innerHeight outerWidth outerHeight <svelte:window> One-way

'group' bindings allow you to capture the current value of a set of radio inputs, or all the selected values of a set of checkbox inputs.

Here is a complete example of using two way bindings with a form:

REPL App.html
<form on:submit="handleSubmit(event)">
	<input bind:value=name type=text>
	<button type=submit>Say hello</button>
</form>

<script>
	export default {
		methods: {
			handleSubmit(event) {
				// prevent the page from reloading
				event.preventDefault();

				const { name } = this.get();
				alert(`Hello ${name}!`);
			}
		}
	};
</script>

Actions

Actions let you decorate elements with additional functionality. Actions are functions which may return an object with lifecycle methods, update and destroy. The action will be called when its element is added to the DOM.

Use actions for things like:

  • tooltips
  • lazy loading images as the page is scrolled, e.g. <img use:lazyload data-src='giant-photo.jpg'/>
  • capturing link clicks for your client router
  • adding drag and drop
REPL App.html
<button on:click="toggleLanguage()" use:tooltip="translations[language].tooltip">
	{language}
</button>

<script>
	export default {
		actions: {
			tooltip(node, text) {
				const tooltip = document.createElement('div');
				tooltip.textContent = text;

				Object.assign(tooltip.style, {
					position: 'absolute',
					background: 'black',
					color: 'white',
					padding: '0.5em 1em',
					fontSize: '12px',
					pointerEvents: 'none',
					transform: 'translate(5px, -50%)',
					borderRadius: '2px',
					transition: 'opacity 0.4s'
				});

				function position() {
					const { top, right, bottom } = node.getBoundingClientRect();
					tooltip.style.top = `${(top + bottom) / 2}px`;
					tooltip.style.left = `${right}px`;
				}

				function append() {
					document.body.appendChild(tooltip);
					tooltip.style.opacity = 0;
					setTimeout(() => tooltip.style.opacity = 1);
					position();
				}

				function remove() {
					tooltip.remove();
				}

				node.addEventListener('mouseenter', append);
				node.addEventListener('mouseleave', remove);

				return {
					update(text) {
						tooltip.textContent = text;
						position();
					},

					destroy() {
						tooltip.remove();
						node.removeEventListener('mouseenter', append);
						node.removeEventListener('mouseleave', remove);
					}
				}
			}
		},

		methods: {
			toggleLanguage() {
				const { language } = this.get();

				this.set({
					language: language === 'english' ? 'latin' : 'english'
				});
			}
		}
	};
</script>

Plugins edit this section

Svelte can be extended with plugins and extra methods.

Transition plugins

The svelte-transitions package includes a selection of officially supported transition plugins, such as fade, fly and slide. You can include them in a component like so:

REPL App.html
<label>
	<input type=checkbox bind:checked=visible> visible
</label>

{#if visible}
	<!-- use `in`, `out`, or `transition` (bidirectional) -->
	<div transition:fly="{y:20}">hello!</div>
{/if}

<script>
	import { fly } from 'svelte-transitions';

	export default {
		transitions: { fly }
	};
</script>

Extra methods

The svelte-extras package includes a handful of methods for tweening (animating), manipulating arrays and so on.

REPL App.html
<input bind:value=newTodo placeholder="buy milk">
<button on:click="push('todos', newTodo)">add todo</button>

<ul>
	{#each todos as todo, i}
		<li>
			<button on:click="splice('todos', i, 1)">x</button>
			{todo}
		</li>
	{/each}
</ul>

<style>
	ul {
		list-style: none;
		padding: 0;
	}

	li button {
		color: rgb(200,0,0);
		background: rgba(200,0,0,0.1);
		border-color: rgba(200,0,0,0.2);
		padding: 0.2em 0.5em;
	}
</style>

<script>
	import { push, splice } from 'svelte-extras';

	export default {
		data() {
			return {
				newTodo: '',
				todos: []
			};
		},

		methods: {
			push,
			splice
		}
	};
</script>

Static properties edit this section

Setup

In some situations, you might want to add static properties to your component constructor. For that, we use the setup property:

REPL App.html
<p>check the console!</p>

<script>
	export default {
		setup(MyComponent) {
			// someone importing this component will be able
			// to access any properties or methods defined here:
			//
			//   import MyComponent from './MyComponent.html';
			//   console.log(MyComponent.ANSWER); // 42
			MyComponent.ANSWER = 42;
		},

		oncreate() {
			console.log('the answer is', this.constructor.ANSWER);
			console.dir(this.constructor);
		}
	};
</script>

preload

If your component definition includes a preload function, it will be attached to the component constructor as a static method. It doesn't change the behaviour of your component in any way — instead, it's a convention that allows systems like Sapper to delay rendering of a component until its data is ready.

See the section on preloading in the Sapper docs for more information.

Server-side rendering edit this section

So far, we've discussed creating Svelte components on the client, which is to say the browser. But you can also render Svelte components in Node.js. This can result in better perceived performance as it means the application starts rendering while the page is still downloading, before any JavaScript executes. It also has SEO advantages in some cases, and can be beneficial for people running older browsers that can't or won't run your JavaScript for whatever reason.

Using the compiler

If you're using the Svelte compiler, whether directly or via an integration like rollup-plugin-svelte or svelte-loader, you can tell it to generate a server-side component by passing the generate: 'ssr' option:

const { js } = svelte.compile(source, {
	generate: 'ssr' // as opposed to 'dom', the default
});

Registering Svelte

Alternatively, an easy way to use the server-side renderer is to register it:

require('svelte/ssr/register');

Now you can require your components:

const Thing = require('./components/Thing.html');

If you prefer to use a different file extension, you can pass options like so:

require('svelte/ssr/register')({
	extensions: ['.svelte']
});

Server-side API

Components have a different API in Node.js – rather than creating instances with set(...) and get() methods, a component is an object with a render(data, options) method:

require('svelte/ssr/register');
const Thing = require('./components/Thing.html');

const data = { answer: 42 };
const { html, css, head } = Thing.render(data);

All your default data, computed properties, helpers and nested components will work as expected.

Any oncreate functions or component methods will not run — these only apply to client-side components.

The SSR compiler will generate a CommonJS module for each of your components – meaning that import and export statements are converted into their require and module.exports equivalents. If your components have non-component dependencies, they must also work as CommonJS modules in Node. If you're using ES2015 modules, we recommend the esm module for automatically converting them to CommonJS.

Using stores

If your components use stores, use the second argument:

const { Store } = require('svelte/store.umd.js');

const { html } = Thing.render(data, {
	store: new Store({
		foo: 'bar'
	})
});

Rendering styles

You can also extract any scoped styles that are used by the component or its children:

const { css } = Thing.render(data);

You could put the resulting css in a separate stylesheet, or include them in the page inside a <style> tag. If you do this, you will probably want to prevent the client-side compiler from including the CSS again. For the CLI, use the --no-css flag. In build tool integrations like rollup-plugin-svelte, pass the css: false option.

Rendering <head> contents

If your component, any of its children, use the <svelte:head> component, you can extract the contents:

const { head } = Thing.render(data);

State management edit this section

Svelte components have built-in state management via the get and set methods. But as your application grows beyond a certain size, you may find that passing data between components becomes laborious.

For example, you might have an <Options> component inside a <Sidebar> component that allows the user to control the behaviour of a <MainView> component. You could use bindings or events to 'send' information up from <Options> through <Sidebar> to a common ancestor — say <App> — which would then have the responsibility of sending it back down to <MainView>. But that's cumbersome, especially if you decide you want to break <MainView> up into a set of smaller components.

Instead, a popular solution to this problem is to use a global store of data that cuts across your component hierarchy. React has Redux and MobX (though these libraries can be used anywhere, including with Svelte), and Vue has Vuex.

Svelte has Store. Store can be used in any JavaScript app, but it's particularly well-suited to Svelte apps.

The basics

Import Store from svelte/store.js (remember to include the curly braces, as it's a named import), then create a new store with some (optional) data:

import { Store } from 'svelte/store.js';

const store = new Store({
	name: 'world'
});

Each instance of Store has get, set, on and fire methods that behave identically to their counterparts on a Svelte component:

const { name } = store.get(); // 'world'

store.on('state', ({ current }) => {
	console.log(`hello ${current.name}`);
});

store.set({ name: 'everybody' }); // 'hello everybody'

Creating components with stores

Let's adapt our very first example:

App.html
<h1>Hello {$name}!</h1>
<Greeting/>

<script>
	import Greeting from './Greeting.html';

	export default {
		components: { Greeting }
	};
</script>
Greeting.html
<p>It's nice to see you, {$name}</p>
main.js
import App from './App.html';
import { Store } from 'svelte/store.js';

const store = new Store({
	name: 'world'
});

const app = new App({
	target: document.querySelector('main'),
	store
});

window.store = store; // useful for debugging!

There are three important things to notice:

  • We're passing store to new App(...) instead of data
  • The template refers to $name instead of name. The $ prefix tells Svelte that name is a store property
  • Because <Greeting> is a child of <App>, it also has access to the store. Without it, <App> would have to pass the name property down as a component property (<Greeting name={name}/>)

Components that depend on store properties will re-render whenever they change.

Declarative stores

As an alternative to adding the store option when instantiating, the component itself can declare a dependency on a store:

REPL App.html
<h1>Hello {$name}!</h1>
<Greeting/>

<script>
	import Greeting from './Greeting.html';
	import store from './store.js';

	export default {
		store: () => store,
		components: { Greeting }
	};
</script>
Greeting.html
<p>It's nice to see you, {$name}</p>
store.js
import { Store } from 'svelte/store.js';
export default new Store({ name: 'world' });

Note that the store option is a function that returns a store, rather than the store itself — this provides greater flexibility.

Computed store properties

Just like components, stores can have computed properties:

store = new Store({
	width: 10,
	height: 10,
	depth: 10,
	density: 3
});

store.compute(
	'volume',
	['width', 'height', 'depth'],
	(width, height, depth) => width * height * depth
);

store.get().volume; // 1000

store.set({ width: 20 });
store.get().volume; // 2000

store.compute(
	'mass',
	['volume', 'density'],
	(volume, density) => volume * density
);

store.get().mass; // 6000

The first argument is the name of the computed property. The second is an array of dependencies — these can be data properties or other computed properties. The third argument is a function that recomputes the value whenever the dependencies change.

A component that was connected to this store could reference {$volume} and {$mass}, just like any other store property.

Accessing the store inside components

Each component gets a reference to this.store. This allows you to attach behaviours in oncreate...

App.html
<script>
	export default {
		oncreate() {
			const listener = this.store.on('state', ({ current }) => {
				// ...
			});

			// listeners are not automatically removed — cancel
			// them to prevent memory leaks
			this.on('destroy', listener.cancel);
		}
	};
</script>

...or call store methods in your event handlers, using the same $ prefix as data properties:

App.html
<button on:click="$set({ muted: true })">
	Mute audio
</button>

Custom store methods

Store doesn't have a concept of actions or commits, like Redux and Vuex. Instead, state is always updated with store.set(...).

You can implement custom logic by subclassing Store:

class TodoStore extends Store {
	addTodo(description) {
		const todo = {
			id: generateUniqueId(),
			done: false,
			description
		};

		const todos = this.get().todos.concat(todo);
		this.set({ todos });
	}

	toggleTodo(id) {
		const todos = this.get().todos.map(todo => {
			if (todo.id === id) {
				return {
					id,
					done: !todo.done,
					description: todo.description
				};
			}

			return todo;
		});

		this.set({ todos });
	}
}

const store = new TodoStore({
	todos: []
});

store.addTodo('Finish writing this documentation');

Methods can update the store asynchronously:

class NasdaqTracker extends Store {
	async fetchStockPrices(ticker) {
		const token = this.token = {};
		const prices = await fetch(`/api/prices/${ticker}`).then(r => r.json());
		if (token !== this.token) return; // invalidated by subsequent request

		this.set({ prices });
	}
}

const store = new NasdaqTracker();
store.fetchStockPrices('AMZN');

You can call these methods in your components, just like the built-in methods:

App.html
<input
	placeholder="Enter a stock ticker"
	on:change="$fetchStockPrices(this.value)"
>

Store bindings

You can bind to store values just like you bind to component values — just add the $ prefix:

App.html
<!-- global audio volume control -->
<input bind:value=$volume type=range min=0 max=1 step=0.01>

Using store properties in computed properties

Just as in templates, you can access store properties in component computed properties by prefixing them with $:

App.html
{#if isVisible}
	<div class="todo {todo.done ? 'done': ''}">
		{todo.description}
	</div>
{/if}

<script>
	export default {
		computed: {
			// `todo` is a component property, `$filter` is
			// a store property
			isVisible: ({ todo, $filter }) => {
				if ($filter === 'all') return true;
				if ($filter === 'done') return todo.done;
				if ($filter === 'pending') return !todo.done;
			}
		}
	};
</script>

Built-in optimisations

The Svelte compiler knows which store properties your components are interested in (because of the $ prefix), and writes code that only listens for changes to those properties. Because of that, you needn't worry about having many properties on your store, even ones that update frequently — components that don't use them will be unaffected.

Preprocessing edit this section

Some developers like to use non-standard languages such as Pug, Sass or CoffeeScript.

It's possible to use these languages, or anything else that can be converted to HTML, CSS and JavaScript, using preprocessors.

svelte.preprocess

Svelte exports a preprocess function that takes some input source code and returns a Promise for a standard Svelte component, ready to be used with svelte.compile:

const svelte = require('svelte');

const input = fs.readFileSync('App.html', 'utf-8');

svelte.preprocess(input, {
	filename: 'App.html', // this is passed to each preprocessor

	markup: ({ content, filename }) => {
		return {
			code: '<!-- some HTML -->',
			map: {...}
		};
	},

	style: ({ content, attributes, filename }) => {
		return {
			code: '/* some CSS */',
			map: {...}
		};
	},

	script: ({ content, attributes, filename }) => {
		return {
			code: '// some JavaScript',
			map: {...}
		};
	}
}).then(preprocessed => {
	fs.writeFileSync('preprocessed/App.html', preprocessed.toString());

	const { js } = svelte.compile(preprocessed);
	fs.writeFileSync('compiled/App.js', js.code);
});

The markup preprocessor, if specified, runs first. The content property represents the entire input string.

The style and script preprocessors receive the contents of the <style> and <script> elements respectively, along with any attributes on those elements (e.g. <style lang='scss'>).

All three preprocessors are optional. Each should return a { code, map } object or a Promise that resolves to a { code, map } object, where code is the resulting string and map is a sourcemap representing the transformation.

The returned map objects are not currently used by Svelte, but will be in future versions

Using build tools

Many build tool plugins, such as rollup-plugin-svelte and svelte-loader, allow you to specify preprocess options, in which case the build tool will do the grunt work.

Advanced edit this section

Keyed each blocks

Associating a key with a block allows Svelte to be smarter about how it adds and removes items to and from a list. To do so, add an (expression) that uniquely identifies each member of the list:

App.html
{#each people as person (person.name)}
	<div>{person.name}</div>
{/each}

It's easier to show the effect of this than to describe it. Open the following example in the REPL:

REPL App.html
<button on:click="update()">update</button>

<section>
	<h2>Keyed</h2>
	{#each people as person (person.name)}
		<div transition:slide>{person.name}</div>
	{/each}
</section>

<section>
	<h2>Non-keyed</h2>
	{#each people as person}
		<div transition:slide>{person.name}</div>
	{/each}
</section>

<style>
	button {
		display: block;
	}

	section {
		width: 10em;
		float: left;
	}
</style>

<script>
	import { slide } from 'svelte-transitions';

	var people = ['Alice', 'Barry', 'Cecilia', 'Douglas', 'Eleanor', 'Felix', 'Grace', 'Horatio', 'Isabelle'];

	function random() {
		return people
			.filter(() => Math.random() < 0.5)
			.map(name => ({ name }))
	}

	export default {
		data() {
			return { people: random() };
		},

		methods: {
			update() {
				this.set({ people: random() });
			}
		},

		transitions: { slide }
	};
</script>

Hydration

If you're using server-side rendering, it's likely that you'll need to create a client-side version of your app on top of the server-rendered version. A naive way to do that would involve removing all the existing DOM and rendering the client-side app in its place:

import App from './App.html';

const target = document.querySelector('#element-with-server-rendered-html');

// avoid doing this!
target.innerHTML = '';
new App({
	target
});

Ideally, we want to reuse the existing DOM instead. This process is called hydration. First, we need to tell the compiler to include the code necessary for hydration to work by passing the hydratable: true option:

const { js } = svelte.compile(source, {
	hydratable: true
});

(Most likely, you'll be passing this option to rollup-plugin-svelte or svelte-loader.)

Then, when we instantiate the client-side component, we tell it to use the existing DOM with hydrate: true:

import App from './App.html';

const target = document.querySelector('#element-with-server-rendered-html');

new App({
	target,
	hydrate: true
});

It doesn't matter if the client-side app doesn't perfectly match the server-rendered HTML — Svelte will repair the DOM as it goes.

Immutable

Because arrays and objects are mutable, Svelte must err on the side of caution when deciding whether or not to update things that refer to them.

But if all your data is immutable, you can use the { immutable: true } compiler option to use strict object comparison (using ===) everywhere in your app. If you have one component that uses immutable data you can set it to use the strict comparison for just that component.

In the example below, searchResults would normally be recalculated whenever items might have changed, but with immutable: true it will only update when items has definitely changed. This can improve the performance of your app.

App.html
{#each searchResults as item}
	<div>{item.name}</div>
{/each}

<script>
	import FuzzySearch from 'fuzzy-search';

	export default {
		immutable: true,

		computed: {
			searchResults: ({ searchString, items }) => {
				if (!searchString) return items;

				const searcher = new FuzzySearch(items, ['name', 'location']);
				return searcher.search(searchString);
			}
		}
	}
</script>

Here's a live example showing the effect of immutable: true.

Custom elements edit this section

Custom elements are an emerging web standard for creating DOM elements that encapsulate styles and behaviours, much like Svelte components. They are part of the web components family of specifications.

Most browsers need polyfills for custom elements. See caniuse for more details

Svelte components can be used as custom elements by doing the following:

  1. Declaring a tag name. The value must contain a hyphen (hello-world in the example below)
  2. Specifying customElement: true in the compiler configuration
HelloWorld.html
<h1>Hello {name}!</h1>

<script>
	export default {
		tag: 'hello-world'
	};
</script>

Importing this file will now register a globally-available <hello-world> custom element that accepts a name property:

import './HelloWorld.html';
document.body.innerHTML = `<hello-world name="world"/>`;

const el = document.querySelector('hello-world');
el.name = 'everybody';

See svelte-custom-elements.surge.sh (source here) for a larger example.

The compiled custom elements are still full-fledged Svelte components and can be used as such:

el.get().name === el.name; // true
el.set({ name: 'folks' }); // equivalent to el.name = 'folks'

One crucial difference is that styles are fully encapsulated — whereas Svelte will prevent component styles from leaking out, custom elements use shadow DOM which also prevents styles from leaking in.

Using <slot>

Custom elements can use slots to place child elements, just like regular Svelte components.

Firing events

You can dispatch events inside custom elements to pass data out:

// inside a component method
const event = new CustomEvent('message', {
	detail: 'Hello parent!',
	bubbles: true,
	cancelable: true,
	composed: true // makes the event jump shadow DOM boundary
});

this.dispatchEvent(event);

Other parts of the application can listen for these events with addEventListener:

const el = document.querySelector('hello-world');
el.addEventListener('message', event => {
	alert(event.detail);
});

Note the composed: true attribute of the custom event. It enables the custom DOM event to cross the shadow DOM boundary and enter into main DOM tree.

Observing properties

Svelte will determine, from the template and computed values, which properties the custom element has — for example, name in our <hello-world> example. You can specify this list of properties manually, for example to restrict which properties are 'visible' to the rest of your app:

export default {
	tag: 'my-thing',
	props: ['foo', 'bar']
};

Compiler options

Earlier, we saw the use of customElement: true to instruct the Svelte compiler to generate a custom element using the tag and (optional) props declared inside the component file.

Alternatively, you can pass tag and props direct to the compiler:

const { js } = svelte.compile(source, {
	customElement: {
		tag: 'overridden-tag-name',
		props: ['yar', 'boo']
	}
});

These options will override the component's own settings, if any.

Transpiling

Miscellaneous edit this section

<noscript>

If you use <noscript> tags in a component, Svelte will only render them in SSR mode. The DOM compiler will strip them out, since you can't create the component without JavaScript, and <noscript> has no effect if JavaScript is available.

TODO... edit this section

This documentation is still a work-in-progress, like Svelte itself. If there are particular things that are missing or could be improved, then please raise an issue on GitHub!