Welcome! This is an auto-generated build of the Svelte tutorial docs, compiled as a one-page document.

Relevant links:

Built at:
2021-12-09T14:11:06.726Z
Commit SHA: 67f79dd934659b9a67b3ec57f191115424d2e589
Netlify deploy status badge

Section: Introduction

Chapter #1 - Basics

💾 Source Code

â„¢ Official Tutorial Page

Welcome to the Svelte tutorial. This will teach you everything you need to know to build fast, small web applications easily.

You can also consult the API docs and the examples, or — if you're impatient to start hacking on your machine locally — the 60-second quickstart.

What is Svelte?

Svelte is a tool for building fast web applications.

It is similar to JavaScript frameworks such as React and Vue, which 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.

How to use this tutorial

You'll need to have basic familiarity with HTML, CSS and JavaScript to understand Svelte.

As you progress through the tutorial, you'll be presented with mini exercises designed to illustrate new features. Later chapters build on the knowledge gained in earlier ones, so it's recommended that you go from start to finish. If necessary, you can navigate via the dropdown above (click 'Introduction / Basics').

Each tutorial chapter will have a 'Show me' button that you can click if you get stuck following the instructions. Try not to rely on it too much; you will learn faster by figuring out where to put each suggested code block and manually typing it in to the editor.

Understanding components

In Svelte, an application is composed from one or more components. A component is a reusable self-contained block of code that encapsulates HTML, CSS and JavaScript that belong together, written into a .svelte file. The 'hello world' example in the code editor is a simple component.

Chapter #2 - Adding data

💾 Source Code

â„¢ Official Tutorial Page

A component that just renders some static markup isn't very interesting. Let's add some data.

First, add a script tag to your component and declare a name variable:

<script>
    let name = 'world';
</script>

<h1>Hello world!</h1>

Then, we can refer to name in the markup:

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

Inside the curly braces, we can put any JavaScript we want. Try changing name to name.toUpperCase() for a shoutier greeting.

Chapter #3 - Dynamic attributes

💾 Source Code

â„¢ Official Tutorial Page

Just like you can use curly braces to control text, you can use them to control element attributes.

Our image is missing a src — let's add one:

<img src={src}>

That's better. But Svelte is giving us a warning:

A11y: <img> element should have an alt attribute

When building web apps, it's important to make sure that they're accessible to the broadest possible userbase, including people with (for example) impaired vision or motion, or people without powerful hardware or good internet connections. Accessibility (shortened to a11y) isn't always easy to get right, but Svelte will help by warning you if you write inaccessible markup.

In this case, we're missing the alt attribute that describes the image for people using screenreaders, or people with slow or flaky internet connections that can't download the image. Let's add one:

<img src={src} alt="A man dances.">

We can use curly braces inside attributes. Try changing it to "{name} dances." — remember to declare a name variable in the <script> block.

Shorthand attributes

It's not uncommon to have an attribute where the name and value are the same, like src={src}. Svelte gives us a convenient shorthand for these cases:

<img {src} alt="A man dances.">

Chapter #4 - Styling

💾 Source Code

â„¢ Official Tutorial Page

Just like in HTML, you can add a <style> tag to your component. Let's add some styles to the <p> element:

<p>This is a paragraph.</p>

<style>
    p {
        color: purple;
        font-family: 'Comic Sans MS', cursive;
        font-size: 2em;
    }
</style>

Importantly, these rules are scoped to the component. You won't accidentally change the style of <p> elements elsewhere in your app, as we'll see in the next step.

Chapter #5 - Nested components

💾 Source Code

â„¢ Official Tutorial Page

It would be impractical to put your entire app in a single component. Instead, we can import components from other files and include them as though we were including elements.

Add a <script> tag that imports Nested.svelte...

<script>
    import Nested from './Nested.svelte';
</script>

...then add it to the markup:

<p>This is a paragraph.</p>
<Nested/>

Notice that even though Nested.svelte has a <p> element, the styles from App.svelte don't leak in.

Also notice that the component name Nested is capitalised. This convention has been adopted to allow us to differentiate between user-defined components and regular HTML tags.

Chapter #6 - HTML tags

💾 Source Code

â„¢ Official Tutorial Page

Ordinarily, strings are inserted as plain text, meaning that characters like < and > have no special meaning.

But sometimes you need to render HTML directly into a component. For example, the words you're reading right now exist in a markdown file that gets included on this page as a blob of HTML.

In Svelte, you do this with the special {@html ...} tag:

<p>{@html string}</p>

Svelte doesn't perform any sanitization of the expression inside {@html ...} before it gets inserted into the DOM. In other words, if you use this feature it's critical that you manually escape HTML that comes from sources you don't trust, otherwise you risk exposing your users to XSS attacks.

Chapter #7 - Making an app

💾 Source Code

â„¢ Official Tutorial Page

This tutorial is designed to get you familiar with the process of writing components. But at some point, you'll want to start writing components in the comfort of your own text editor.

First, you'll need to integrate Svelte with a build tool. There are officially maintained plugins for Vite, Rollup and webpack...

...and a variety of community-maintained ones.

Don't worry if you're relatively new to web development and haven't used these tools before. We've prepared a simple step-by-step guide, Svelte for new developers, which walks you through the process.

You'll also want to configure your text editor. If you're using VS Code, install the Svelte extension, otherwise follow this guide to configure your text editor to treat .svelte files the same as .html for the sake of syntax highlighting.

Then, once you've got your project set up, using Svelte components is easy. The compiler turns each component into a regular JavaScript class — just import it and instantiate with new:

import App from './App.svelte';

const app = new App({
    target: document.body,
    props: {
        // we'll learn about props later
        answer: 42
    }
});

You can then interact with app using the component API if you need to.

Section: Reactivity

Chapter #1 - Assignments

💾 Source Code

â„¢ Official Tutorial Page

At the heart of Svelte is a powerful system of reactivity for keeping the DOM in sync with your application state — for example, in response to an event.

To demonstrate it, we first need to wire up an event handler. Replace line 9 with this:

<button on:click={incrementCount}>

Inside the incrementCount function, all we need to do is change the value of count:

function incrementCount() {
    count += 1;
}

Svelte 'instruments' this assignment with some code that tells it the DOM will need to be updated.

Chapter #2 - Declarations

💾 Source Code

â„¢ Official Tutorial Page

Svelte automatically updates the DOM when your component's state changes. Often, some parts of a component's state need to be computed from other parts (such as a fullname derived from a firstname and a lastname), and recomputed whenever they change.

For these, we have reactive declarations. They look like this:

let count = 0;
$: doubled = count * 2;

Don't worry if this looks a little alien. It's valid (if unconventional) JavaScript, which Svelte interprets to mean 're-run this code whenever any of the referenced values change'. Once you get used to it, there's no going back.

Let's use doubled in our markup:

<p>{count} doubled is {doubled}</p>

Of course, you could just write {count * 2} in the markup instead — you don't have to use reactive values. Reactive values become particularly valuable when you need to reference them multiple times, or you have values that depend on other reactive values.

Chapter #3 - Statements

💾 Source Code

â„¢ Official Tutorial Page

We're not limited to declaring reactive values — we can also run arbitrary statements reactively. For example, we can log the value of count whenever it changes:

$: console.log('the count is ' + count);

You can easily group statements together with a block:

$: {
    console.log('the count is ' + count);
    alert('I SAID THE COUNT IS ' + count);
}

You can even put the $: in front of things like if blocks:

$: if (count >= 10) {
    alert('count is dangerously high!');
    count = 9;
}

Chapter #4 - Updating arrays and objects

💾 Source Code

â„¢ Official Tutorial Page

Because Svelte's reactivity is triggered by assignments, using array methods like push and splice won't automatically cause updates. For example, clicking the button doesn't do anything.

One way to fix that is to add an assignment that would otherwise be redundant:

function addNumber() {
    numbers.push(numbers.length + 1);
    numbers = numbers;
}

But there's a more idiomatic solution:

function addNumber() {
    numbers = [...numbers, numbers.length + 1];
}

You can use similar patterns to replace pop, shift, unshift and splice.

Assignments to properties of arrays and objects — e.g. obj.foo += 1 or array[i] = x — work the same way as assignments to the values themselves.

function addNumber() {
    numbers[numbers.length] = numbers.length + 1;
}

A simple rule of thumb: the name of the updated variable must appear on the left hand side of the assignment. For example this...

const foo = obj.foo;
foo.bar = 'baz';

...won't trigger reactivity on obj.foo.bar, unless you follow it up with obj = obj.

Section: Props

Chapter #1 - Declaring props

💾 Source Code

â„¢ Official Tutorial Page

So far, we've dealt exclusively with internal state — that is to say, the values are only accessible within a given component.

In any real application, you'll need to pass data from one component down to its children. To do that, we need to declare properties, generally shortened to 'props'. In Svelte, we do that with the export keyword. Edit the Nested.svelte component:

<script>
    export let answer;
</script>

Just like $:, this may feel a little weird at first. That's not how export normally works in JavaScript modules! Just roll with it for now — it'll soon become second nature.

Chapter #2 - Default values

💾 Source Code

â„¢ Official Tutorial Page

We can easily specify default values for props in Nested.svelte:

<script>
    export let answer = 'a mystery';
</script>

If we now add a second component without an answer prop, it will fall back to the default:

<Nested answer={42}/>
<Nested/>

Chapter #3 - Spread props

💾 Source Code

â„¢ Official Tutorial Page

If you have an object of properties, you can 'spread' them onto a component instead of specifying each one:

<Info {...pkg}/>

Conversely, if you need to reference all the props that were passed into a component, including ones that weren't declared with export, you can do so by accessing $props directly. It's not generally recommended, as it's difficult for Svelte to optimise, but it's useful in rare cases.

Section: Logic

Chapter #1 - If blocks

💾 Source Code

â„¢ Official Tutorial Page

HTML doesn't have a way of expressing logic, like conditionals and loops. Svelte does.

To conditionally render some markup, we wrap it in an if block:

{##if user.loggedIn}
    <button on:click={toggle}>
        Log out
    </button>
{/if}

{##if !user.loggedIn}
    <button on:click={toggle}>
        Log in
    </button>
{/if}

Try it — update the component, and click on the buttons.

Chapter #2 - Else blocks

💾 Source Code

â„¢ Official Tutorial Page

Since the two conditions — if user.loggedIn and if !user.loggedIn — are mutually exclusive, we can simplify this component slightly by using an else block:

{##if user.loggedIn}
    <button on:click={toggle}>
        Log out
    </button>
{:else}
    <button on:click={toggle}>
        Log in
    </button>
{/if}

A ## character always indicates a block opening tag. A / character always indicates a block closing tag. A : character, as in {:else}, indicates a block continuation tag. Don't worry — you've already learned almost all the syntax Svelte adds to HTML.

Chapter #3 - Else-if blocks

💾 Source Code

â„¢ Official Tutorial Page

Multiple conditions can be 'chained' together with else if:

{##if x > 10}
    <p>{x} is greater than 10</p>
{:else if 5 > x}
    <p>{x} is less than 5</p>
{:else}
    <p>{x} is between 5 and 10</p>
{/if}

Chapter #4 - Each blocks

💾 Source Code

â„¢ Official Tutorial Page

If you need to loop over lists of data, use an each block:

<ul>
    {##each cats as cat}
        <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
            {cat.name}
        </a></li>
    {/each}
</ul>

The expression (cats, in this case) can be any array or array-like object (i.e. it has a length property). You can loop over generic iterables with each [...iterable].

You can get the current index as a second argument, like so:

{##each cats as cat, i}
    <li><a target="_blank" href="https://www.youtube.com/watch?v={cat.id}">
        {i + 1}: {cat.name}
    </a></li>
{/each}

If you prefer, you can use destructuring — each cats as { id, name } — and replace cat.id and cat.name with id and name.

Chapter #5 - Keyed each blocks

💾 Source Code

â„¢ Official Tutorial Page

By default, when you modify the value of an each block, it will add and remove items at the end of the block, and update any values that have changed. That might not be what you want.

It's easier to show why than to explain. Click the 'Remove first thing' button a few times, and notice what happens: It removes the first <Thing> component, but the last DOM node. Then it updates the name value in the remaining DOM nodes, but not the emoji.

Instead, we'd like to remove only the first <Thing> component and its DOM node, and leave the others unaffected.

To do that, we specify a unique identifier (or "key") for the each block:

{##each things as thing (thing.id)}
    <Thing name={thing.name}/>
{/each}

Here, (thing.id) is the key, which tells Svelte how to figure out which DOM node to change when the component updates.

You can use any object as the key, as Svelte uses a Map internally — in other words you could do (thing) instead of (thing.id). Using a string or number is generally safer, however, since it means identity persists without referential equality, for example when updating with fresh data from an API server.

Chapter #6 - Await blocks

💾 Source Code

â„¢ Official Tutorial Page

Most web applications have to deal with asynchronous data at some point. Svelte makes it easy to await the value of promises directly in your markup:

{##await promise}
    <p>...waiting</p>
{:then number}
    <p>The number is {number}</p>
{:catch error}
    <p style="color: red">{error.message}</p>
{/await}

Only the most recent promise is considered, meaning you don't need to worry about race conditions.

If you know that your promise can't reject, you can omit the catch block. You can also omit the first block if you don't want to show anything until the promise resolves:

{##await promise then value}
    <p>the value is {value}</p>
{/await}

Section: Events

Chapter #1 - DOM events

💾 Source Code

â„¢ Official Tutorial Page

As we've briefly seen already, you can listen to any event on an element with the on: directive:

<div on:mousemove={handleMousemove}>
    The mouse position is {m.x} x {m.y}
</div>

Chapter #2 - Inline handlers

💾 Source Code

â„¢ Official Tutorial Page

You can also declare event handlers inline:

<div on:mousemove="{e => m = { x: e.clientX, y: e.clientY }}">
    The mouse position is {m.x} x {m.y}
</div>

The quote marks are optional, but they're helpful for syntax highlighting in some environments.

In some frameworks you may see recommendations to avoid inline event handlers for performance reasons, particularly inside loops. That advice doesn't apply to Svelte — the compiler will always do the right thing, whichever form you choose.

Chapter #3 - Event modifiers

💾 Source Code

â„¢ Official Tutorial Page

DOM event handlers can have modifiers that alter their behaviour. For example, a handler with a once modifier will only run a single time:

<script>
    function handleClick() {
        alert('no more alerts')
    }
</script>

<button on:click|once={handleClick}>
    Click me
</button>

The full list of modifiers:

You can chain modifiers together, e.g. on:click|once|capture={...}.

Chapter #4 - Component events

💾 Source Code

â„¢ Official Tutorial Page

Components can also dispatch events. To do so, they must create an event dispatcher. Update Inner.svelte:

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

    const dispatch = createEventDispatcher();

    function sayHello() {
        dispatch('message', {
            text: 'Hello!'
        });
    }
</script>

createEventDispatcher must be called when the component is first instantiated — you can't do it later inside e.g. a setTimeout callback. This links dispatch to the component instance.

Notice that the App component is listening to the messages dispatched by Inner component thanks to the on:message directive. This directive is an attribute prefixed with on: followed by the event name that we are dispatching (in this case, message).

Without this attribute, messages would still be dispatched, but the App would not react to it. You can try removing the on:message attribute and pressing the button again.

You can also try changing the event name to something else. For instance, change dispatch('message') to dispatch('myevent') in Inner.svelte and change the attribute name from on:message to on:myevent in the App.svelte component.

Chapter #5 - Event forwarding

💾 Source Code

â„¢ Official Tutorial Page

Unlike DOM events, component events don't bubble. If you want to listen to an event on some deeply nested component, the intermediate components must forward the event.

In this case, we have the same App.svelte and Inner.svelte as in the previous chapter, but there's now an Outer.svelte component that contains <Inner/>.

One way we could solve the problem is adding createEventDispatcher to Outer.svelte, listening for the message event, and creating a handler for it:

<script>
    import Inner from './Inner.svelte';
    import { createEventDispatcher } from 'svelte';

    const dispatch = createEventDispatcher();

    function forward(event) {
        dispatch('message', event.detail);
    }
</script>

<Inner on:message={forward}/>

But that's a lot of code to write, so Svelte gives us an equivalent shorthand — an on:message event directive without a value means 'forward all message events'.

<script>
    import Inner from './Inner.svelte';
</script>

<Inner on:message/>

Chapter #6 - DOM event forwarding

💾 Source Code

â„¢ Official Tutorial Page

Event forwarding works for DOM events too.

We want to get notified of clicks on our <CustomButton> — to do that, we just need to forward click events on the <button> element in CustomButton.svelte:

<button on:click>
    Click me
</button>

Section: Bindings

Chapter #1 - Text inputs

💾 Source Code

â„¢ Official Tutorial Page

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.

Sometimes it's useful to break that rule. Take the case of the <input> element in this component — we could add an on:input event handler that sets the value of name to event.target.value, but it's a bit... boilerplatey. It gets even worse with other form elements, as we'll see.

Instead, we can use the bind:value directive:

<input bind:value={name}>

This means that not only will changes to the value of name update the input value, but changes to the input value will update name.

Chapter #2 - Numeric inputs

💾 Source Code

â„¢ Official Tutorial Page

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:

<input type=number bind:value={a} min=0 max=10>
<input type=range bind:value={a} min=0 max=10>

Chapter #3 - Checkbox inputs

💾 Source Code

â„¢ Official Tutorial Page

Checkboxes are used for toggling between states. Instead of binding to input.value, we bind to input.checked:

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

Chapter #4 - Group inputs

💾 Source Code

â„¢ Official Tutorial Page

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:

<input type=radio bind:group={scoops} name="scoops" value={1}>

In this case, we could make the code simpler by moving the checkbox inputs into an each block. First, add a menu variable to the <script> block...

let menu = [
    'Cookies and cream',
    'Mint choc chip',
    'Raspberry ripple'
];

...then replace the second section:

<h2>Flavours</h2>

{##each menu as flavour}
    <label>
        <input type=checkbox bind:group={flavours} name="flavours" value={flavour}>
        {flavour}
    </label>
{/each}

It's now easy to expand our ice cream menu in new and exciting directions.

Chapter #5 - Textarea inputs

💾 Source Code

â„¢ Official Tutorial Page

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.

Chapter #6 - Select bindings

💾 Source Code

â„¢ Official Tutorial Page

We can also use bind:value with <select> elements. Update line 20:

<select bind:value={selected} on:change="{() => answer = ''}">

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.

Chapter #7 - Select multiple

💾 Source Code

â„¢ Official Tutorial Page

A select can have a multiple attribute, in which case it will populate an array rather than selecting a single value.

Returning to our earlier ice cream example, 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>

Press and hold the control key (or the command key on MacOS) for selecting multiple options.

Chapter #8 - Contenteditable bindings

💾 Source Code

â„¢ Official Tutorial Page

Elements with a contenteditable="true" attribute support textContent and innerHTML bindings:

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

Chapter #9 - Each block bindings

💾 Source Code

â„¢ Official Tutorial Page

You can even bind to properties inside an each block.

{##each todos as todo}
    <input
        type=checkbox
        bind:checked={todo.done}
    >

    <input
        placeholder="What needs to be done?"
        bind:value={todo.text}
    >
{/each}

Note that interacting with these <input> elements will mutate the array. If you prefer to work with immutable data, you should avoid these bindings and use event handlers instead.

Chapter #10 - Media elements

💾 Source Code

â„¢ Official Tutorial Page

The <audio> and <video> elements have several properties that you can bind to. This example demonstrates a few of them.

On line 62, add currentTime={time}, duration and paused bindings:

<video
    poster="https://sveltejs.github.io/assets/caminandes-llamigos.jpg"
    src="https://sveltejs.github.io/assets/caminandes-llamigos.mp4"
    on:mousemove={handleMove}
    on:touchmove|preventDefault={handleMove}
    on:mousedown={handleMousedown}
    on:mouseup={handleMouseup}
    bind:currentTime={time}
    bind:duration
    bind:paused>
    <track kind="captions">
</video>

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.

Ordinarily on the web, you would track currentTime by listening for timeupdate events. But these events fire too infrequently, resulting in choppy UI. Svelte does better — it checks currentTime using requestAnimationFrame.

The complete set of bindings for <audio> and <video> is as follows — six readonly bindings...

...and five two-way bindings:

Videos additionally have readonly videoWidth and videoHeight bindings.

Chapter #11 - Dimensions

💾 Source Code

â„¢ Official Tutorial Page

Every block-level element has clientWidth, clientHeight, offsetWidth and offsetHeight bindings:

<div bind:clientWidth={w} bind:clientHeight={h}>
    <span style="font-size: {size}px">{text}</span>
</div>

These bindings are readonly — changing the values of w and h won't have any effect.

Elements are measured using a technique similar to this one. There is some overhead involved, so it's not recommended to use this for large numbers of elements.

display: inline elements cannot be measured with this approach; nor can elements that can't contain other elements (such as <canvas>). In these cases you will need to measure a wrapper element instead.

Chapter #12 - This

💾 Source Code

â„¢ Official Tutorial Page

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 lifecycle function.

Chapter #13 - Component bindings

💾 Source Code

â„¢ Official Tutorial Page

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> 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.

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'.

Chapter #14 - Binding to component instances

💾 Source Code

â„¢ Official Tutorial Page

Just as you can bind to DOM elements, you can bind to component instances themselves. For example, we can bind the instance of <InputField> to a variable named field in the same way we did when binding DOM Elements

<script>
    let field;
</script>

<InputField bind:this={field} />

Now we can programmatically interact with this component using field.

<button on:click="{() => field.focus()}">
    Focus field
</button>

Note that we can't do {field.focus} since field is undefined when the button is first rendered and throws an error.

Section: Lifecycle

Chapter #1 - onMount

💾 Source Code

â„¢ Official Tutorial Page

Every component has a lifecycle that starts when it is created, and ends when it is destroyed. There are a handful of functions that allow you to run code at key moments during that lifecycle.

The one you'll use most frequently is onMount, which runs after the component is first rendered to the DOM. We briefly encountered it earlier when we needed to interact with a <canvas> element after it had been rendered.

We'll add an onMount handler that loads some data over the network:

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

    let photos = [];

    onMount(async () => {
        const res = await fetch(`https://jsonplaceholder.typicode.com/photos?_limit=20`);
        photos = await res.json();
    });
</script>

It's recommended to put the fetch in onMount rather than at the top level of the <script> because of server-side rendering (SSR). With the exception of onDestroy, lifecycle functions don't run during SSR, which means we can avoid fetching data that should be loaded lazily once the component has been mounted in the DOM.

Lifecycle functions must be called while the component is initialising so that the callback is bound to the component instance — not (say) in a setTimeout.

If the onMount callback returns a function, that function will be called when the component is destroyed.

Chapter #2 - onDestroy

💾 Source Code

â„¢ Official Tutorial Page

To run code when your component is destroyed, use onDestroy.

For example, we can add a setInterval function when our component initialises, and clean it up when it's no longer relevant. Doing so prevents memory leaks.

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

    let counter = 0;
    const interval = setInterval(() => counter += 1, 1000);

    onDestroy(() => clearInterval(interval));
</script>

While it's important to call lifecycle functions during the component's initialisation, it doesn't matter where you call them from. So if we wanted, we could abstract the interval logic into a helper function in utils.js...

import { onDestroy } from 'svelte';

export function onInterval(callback, milliseconds) {
    const interval = setInterval(callback, milliseconds);

    onDestroy(() => {
        clearInterval(interval);
    });
}

...and import it into our component:

<script>
    import { onInterval } from './utils.js';

    let counter = 0;
    onInterval(() => counter += 1, 1000);
</script>

Open and close the timer a few times and make sure the counter keeps ticking and the CPU load increases. This is due to a memory leak as the previous timers are not deleted. Don't forget to refresh the page before solving the example.

Chapter #3 - beforeUpdate and afterUpdate

💾 Source Code

â„¢ Official Tutorial Page

The beforeUpdate function schedules work to happen immediately before the DOM is updated. afterUpdate is its counterpart, used for running code once the DOM is in sync with your data.

Together, they're useful for doing things imperatively that are difficult to achieve in a purely state-driven way, like updating the scroll position of an element.

This Eliza chatbot is annoying to use, because you have to keep scrolling the chat window. Let's fix that.

let div;
let autoscroll;

beforeUpdate(() => {
    autoscroll = div && (div.offsetHeight + div.scrollTop) > (div.scrollHeight - 20);
});

afterUpdate(() => {
    if (autoscroll) div.scrollTo(0, div.scrollHeight);
});

Note that beforeUpdate will first run before the component has mounted, so we need to check for the existence of div before reading its properties.

Chapter #4 - tick

💾 Source Code

â„¢ Official Tutorial Page

The tick function is unlike other lifecycle functions in that you can call it any time, not just when the component first initialises. It returns a promise that resolves as soon as any pending state changes have been applied to the DOM (or immediately, if there are no pending state changes).

When you update component state in Svelte, it doesn't update the DOM immediately. Instead, it waits until the next microtask to see if there are any other changes that need to be applied, including in other components. Doing so avoids unnecessary work and allows the browser to batch things more effectively.

You can see that behaviour in this example. Select a range of text and hit the tab key. Because the <textarea> value changes, the current selection is cleared and the cursor jumps, annoyingly, to the end. We can fix this by importing tick...

import { tick } from 'svelte';

...and running it immediately before we set this.selectionStart and this.selectionEnd at the end of handleKeydown:

await tick();
this.selectionStart = selectionStart;
this.selectionEnd = selectionEnd;

Section: Stores

Chapter #1 - Writable stores

💾 Source Code

â„¢ Official Tutorial Page

Not all application state belongs inside your application's component hierarchy. Sometimes, you'll have values that need to be accessed by multiple unrelated components, or by a regular JavaScript module.

In Svelte, we do this with stores. A store is simply an object with a subscribe method that allows interested parties to be notified whenever the store value changes. In App.svelte, count is a store, and we're setting count_value in the count.subscribe callback.

Click the stores.js tab to see the definition of count. It's a writable store, which means it has set and update methods in addition to subscribe.

Now go to the Incrementer.svelte tab so that we can wire up the + button:

function increment() {
    count.update(n => n + 1);
}

Clicking the + button should now update the count. Do the inverse for Decrementer.svelte.

Finally, in Resetter.svelte, implement reset:

function reset() {
    count.set(0);
}

Chapter #2 - Auto-subscriptions

💾 Source Code

â„¢ Official Tutorial Page

The app in the previous example works, but there's a subtle bug — the store is subscribed to, but never unsubscribed. If the component was instantiated and destroyed many times, this would result in a memory leak.

Start by declaring unsubscribe in App.svelte:

const unsubscribe = count.subscribe(value => {
    count_value = value;
});

Calling a subscribe method returns an unsubscribe function.

You now declared unsubscribe, but it still needs to be called, for example through the onDestroy lifecycle hook:

<script>
    import { onDestroy } from 'svelte';
    import { count } from './stores.js';
    import Incrementer from './Incrementer.svelte';
    import Decrementer from './Decrementer.svelte';
    import Resetter from './Resetter.svelte';

    let count_value;

    const unsubscribe = count.subscribe(value => {
        count_value = value;
    });

    onDestroy(unsubscribe);
</script>

<h1>The count is {count_value}</h1>

It starts to get a bit boilerplatey though, especially if your component subscribes to multiple stores. Instead, Svelte has a trick up its sleeve — you can reference a store value by prefixing the store name with $:

<script>
    import { count } from './stores.js';
    import Incrementer from './Incrementer.svelte';
    import Decrementer from './Decrementer.svelte';
    import Resetter from './Resetter.svelte';
</script>

<h1>The count is {$count}</h1>

Auto-subscription only works with store variables that are declared (or imported) at the top-level scope of a component.

You're not limited to using $count inside the markup, either — you can use it anywhere in the <script> as well, such as in event handlers or reactive declarations.

Any name beginning with $ is assumed to refer to a store value. It's effectively a reserved character — Svelte will prevent you from declaring your own variables with a $ prefix.

Chapter #3 - Readable stores

💾 Source Code

â„¢ Official Tutorial Page

Not all stores should be writable by whoever has a reference to them. For example, you might have a store representing the mouse position or the user's geolocation, and it doesn't make sense to be able to set those values from 'outside'. For those cases, we have readable stores.

Click over to the stores.js tab. The first argument to readable is an initial value, which can be null or undefined if you don't have one yet. The second argument is a start function that takes a set callback and returns a stop function. The start function is called when the store gets its first subscriber; stop is called when the last subscriber unsubscribes.

export const time = readable(new Date(), function start(set) {
    const interval = setInterval(() => {
        set(new Date());
    }, 1000);

    return function stop() {
        clearInterval(interval);
    };
});

Chapter #4 - Derived stores

💾 Source Code

â„¢ Official Tutorial Page

You can create a store whose value is based on the value of one or more other stores with derived. Building on our previous example, we can create a store that derives the time the page has been open:

export const elapsed = derived(
    time,
    $time => Math.round(($time - start) / 1000)
);

It's possible to derive a store from multiple inputs, and to explicitly set a value instead of returning it (which is useful for deriving values asynchronously). Consult the API reference for more information.

Chapter #5 - Custom stores

💾 Source Code

â„¢ Official Tutorial Page

As long as an object correctly implements the subscribe method, it's a store. Beyond that, anything goes. It's very easy, therefore, to create custom stores with domain-specific logic.

For example, the count store from our earlier example could include increment, decrement and reset methods and avoid exposing set and update:

function createCount() {
    const { subscribe, set, update } = writable(0);

    return {
        subscribe,
        increment: () => update(n => n + 1),
        decrement: () => update(n => n - 1),
        reset: () => set(0)
    };
}

Chapter #6 - Store bindings

💾 Source Code

â„¢ Official Tutorial Page

If a store is writable — i.e. it has a set method — you can bind to its value, just as you can bind to local component state.

In this example we have a writable store name and a derived store greeting. Update the <input> element:

<input bind:value={$name}>

Changing the input value will now update name and all its dependents.

We can also assign directly to store values inside a component. Add a <button> element:

<button on:click="{() => $name += '!'}">
    Add exclamation mark!
</button>

The $name += '!' assignment is equivalent to name.set($name + '!').

Section: Motion

Chapter #1 - Tweened

💾 Source Code

â„¢ Official Tutorial Page

Setting values and watching the DOM update automatically is cool. Know what's even cooler? Tweening those values. Svelte includes tools to help you build slick user interfaces that use animation to communicate changes.

Let's start by changing the progress store to a tweened value:

<script>
    import { tweened } from 'svelte/motion';

    const progress = tweened(0);
</script>

Clicking the buttons causes the progress bar to animate to its new value. It's a bit robotic and unsatisfying though. We need to add an easing function:

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

    const progress = tweened(0, {
        duration: 400,
        easing: cubicOut
    });
</script>

The svelte/easing module contains the Penner easing equations, or you can supply your own p => t function where p and t are both values between 0 and 1.

The full set of options available to tweened:

You can also pass these options to progress.set and progress.update as a second argument, in which case they will override the defaults. The set and update methods both return a promise that resolves when the tween completes.

Chapter #2 - Spring

💾 Source Code

â„¢ Official Tutorial Page

The spring function is an alternative to tweened that often works better for values that are frequently changing.

In this example we have two stores — one representing the circle's coordinates, and one representing its size. Let's convert them to springs:

<script>
    import { spring } from 'svelte/motion';

    let coords = spring({ x: 50, y: 50 });
    let size = spring(10);
</script>

Both springs have default stiffness and damping values, which control the spring's, well... springiness. We can specify our own initial values:

let coords = spring({ x: 50, y: 50 }, {
    stiffness: 0.1,
    damping: 0.25
});

Waggle your mouse around, and try dragging the sliders to get a feel for how they affect the spring's behaviour. Notice that you can adjust the values while the spring is still in motion.

Section: Transitions

Chapter #1 - The transition directive

💾 Source Code

â„¢ Official Tutorial Page

We can make more appealing user interfaces by gracefully transitioning elements into and out of the DOM. Svelte makes this very easy with the transition directive.

First, import the fade function from svelte/transition...

<script>
    import { fade } from 'svelte/transition';
    let visible = true;
</script>

...then add it to the <p> element:

<p transition:fade>Fades in and out</p>

Chapter #2 - Adding parameters

💾 Source Code

â„¢ Official Tutorial Page

Transition functions can accept parameters. Replace the fade transition with fly...

<script>
    import { fly } from 'svelte/transition';
    let visible = true;
</script>

...and apply it to the <p> along with some options:

<p transition:fly="{{ y: 200, duration: 2000 }}">
    Flies in and out
</p>

Note that the transition is reversible — if you toggle the checkbox while the transition is ongoing, it transitions from the current point, rather than the beginning or the end.

Chapter #3 - In and out

💾 Source Code

â„¢ Official Tutorial Page

Instead of the transition directive, an element can have an in or an out directive, or both together. Import fade alongside fly...

import { fade, fly } from 'svelte/transition';

...then replace the transition directive with separate in and out directives:

<p in:fly="{{ y: 200, duration: 2000 }}" out:fade>
    Flies in, fades out
</p>

In this case, the transitions are not reversed.

Chapter #4 - Custom CSS transitions

💾 Source Code

â„¢ Official Tutorial Page

The svelte/transition module has a handful of built-in transitions, but it's very easy to create your own. By way of example, this is the source of the fade transition:

function fade(node, {
    delay = 0,
    duration = 400
}) {
    const o = +getComputedStyle(node).opacity;

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

The function takes two arguments — the node to which the transition is applied, and any parameters that were passed in — and returns a transition object which can have the following properties:

The t value is 0 at the beginning of an intro or the end of an outro, and 1 at the end of an intro or beginning of an outro.

Most of the time you should return the css property and not the tick property, as CSS animations run off the main thread to prevent jank where possible. Svelte 'simulates' the transition and constructs a CSS animation, then lets it run.

For example, the fade transition generates a CSS animation somewhat like this:

0% { opacity: 0 }
10% { opacity: 0.1 }
20% { opacity: 0.2 }
/* ... */
100% { opacity: 1 }

We can get a lot more creative though. Let's make something truly gratuitous:

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

    let visible = true;

    function spin(node, { duration }) {
        return {
            duration,
            css: t => {
                const eased = elasticOut(t);

                return `
                    transform: scale(${eased}) rotate(${eased * 1080}deg);
                    color: hsl(
                        ${Math.trunc(t * 360)},
                        ${Math.min(100, 1000 - 1000 * t)}%,
                        ${Math.min(50, 500 - 500 * t)}%
                    );`
            }
        };
    }
</script>

Remember: with great power comes great responsibility.

Chapter #5 - Custom JS transitions

💾 Source Code

â„¢ Official Tutorial Page

While you should generally use CSS for transitions as much as possible, there are some effects that can't be achieved without JavaScript, such as a typewriter effect:

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 = Math.trunc(text.length * t);
            node.textContent = text.slice(0, i);
        }
    };
}

Chapter #6 - Transition events

💾 Source Code

â„¢ Official Tutorial Page

It can be useful to know when transitions are beginning and ending. Svelte dispatches events that you can listen to like any other DOM event:

<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>

Chapter #7 - Local transitions

💾 Source Code

â„¢ Official Tutorial Page

Ordinarily, transitions will play on elements when any container block is added or destroyed. In the example here, toggling the visibility of the entire list also applies transitions to individual list elements.

Instead, we'd like transitions to play only when individual items are added and removed — in other words, when the user drags the slider.

We can achieve this with a local transition, which only plays when the block with the transition itself is added or removed:

<div transition:slide|local>
    {item}
</div>

Chapter #8 - Deferred transitions

💾 Source Code

â„¢ Official Tutorial Page

A particularly powerful feature of Svelte's transition engine is the ability to defer transitions, so that they can be coordinated between multiple elements.

Take this pair of todo lists, in which toggling a todo sends it to the opposite list. In the real world, objects don't behave like that — instead of disappearing and reappearing in another place, they move through a series of intermediate positions. Using motion can go a long way towards helping users understand what's happening in your app.

We can achieve this effect using the crossfade function, which creates a pair of transitions called send and receive. When an element is 'sent', it looks for a corresponding element being 'received', and generates a transition that transforms the element to its counterpart's position and fades it out. When an element is 'received', the reverse happens. If there is no counterpart, the fallback transition is used.

Find the <label> element on line 65, and add the send and receive transitions:

<label
    in:receive="{{key: todo.id}}"
    out:send="{{key: todo.id}}"
>

Do the same for the next <label> element:

<label
    class="done"
    in:receive="{{key: todo.id}}"
    out:send="{{key: todo.id}}"
>

Now, when you toggle items, they move smoothly to their new location. The non-transitioning items still jump around awkwardly — we can fix that in the next chapter.

Chapter #9 - Key blocks

💾 Source Code

â„¢ Official Tutorial Page

Key blocks destroy and recreate their contents when the value of an expression changes.

{##key value}
    <div transition:fade>{value}</div>
{/key}

This is useful if you want an element to play its transition whenever a value changes instead of only when the element enters or leaves the DOM.

Wrap the <span> element in a key block depending on number. This will make the animation play whenever you press the increment button.

Section: Animations

Chapter #1 - The animate directive

💾 Source Code

â„¢ Official Tutorial Page

In the previous chapter, we used deferred transitions to create the illusion of motion as elements move from one todo list to the other.

To complete the illusion, we also need to apply motion to the elements that aren't transitioning. For this, we use the animate directive.

First, import the flip function — flip stands for 'First, Last, Invert, Play' — from svelte/animate:

import { flip } from 'svelte/animate';

Then add it to the <label> elements:

<label
    in:receive="{{key: todo.id}}"
    out:send="{{key: todo.id}}"
    animate:flip
>

The movement is a little slow in this case, so we can add a duration parameter:

<label
    in:receive="{{key: todo.id}}"
    out:send="{{key: todo.id}}"
    animate:flip="{{duration: 200}}"
>

duration can also be a d => milliseconds function, where d is the number of pixels the element has to travel

Note that all the transitions and animations are being applied with CSS, rather than JavaScript, meaning they won't block (or be blocked by) the main thread.

Section: Actions

Chapter #1 - The use directive

💾 Source Code

â„¢ Official Tutorial Page

Actions are essentially element-level lifecycle functions. They're useful for things like:

In this app, we want to make the orange modal close when the user clicks outside it. It has an event handler for the outclick event, but it isn't a native DOM event. We have to dispatch it ourselves. First, import the clickOutside function...

import { clickOutside } from "./click_outside.js";

...then use it with the element:

<div class="box" use:clickOutside on:outclick="{() => (showModal = false)}">
    Click outside me!
</div>

Open the click_outside.js file. Like transition functions, an action function receives a node (which is the element that the action is applied to) and some optional parameters, and returns an action object. That object can have a destroy function, which is called when the element is unmounted.

We want to fire the outclick event when the user clicks outside the orange box. One possible implementation looks like this:

export function clickOutside(node) {
    const handleClick = (event) => {
        if (!node.contains(event.target)) {
            node.dispatchEvent(new CustomEvent("outclick"));
        }
    };

    document.addEventListener("click", handleClick, true);

    return {
        destroy() {
            document.removeEventListener("click", handleClick, true);
        },
    };
}

Update the clickOutside function, click the button to show the modal and then click outside it to close it.

Chapter #2 - Adding parameters

💾 Source Code

â„¢ Official Tutorial Page

Like transitions and animations, an action can take an argument, which the action function will be called with alongside the element it belongs to.

Here, we're using a longpress action that fires an event with the same name whenever the user presses and holds the button for a given duration. Right now, if you switch over to the longpress.js file, you'll see it's hardcoded to 500ms.

We can change the action function to accept a duration as a second argument, and pass that duration to the setTimeout call:

export function longpress(node, duration) {
    // ...

    const handleMousedown = () => {
        timer = setTimeout(() => {
            node.dispatchEvent(
                new CustomEvent('longpress')
            );
        }, duration);
    };

    // ...
}

Back in App.svelte, we can pass the duration value to the action:

<button use:longpress={duration}

This almost works — the event now only fires after 2 seconds. But if you slide the duration down, it will still take two seconds.

To change that, we can add an update method in longpress.js. This will be called whenever the argument changes:

return {
    update(newDuration) {
        duration = newDuration;
    },
    // ...
};

If you need to pass multiple arguments to an action, combine them into a single object, as in use:longpress={{duration, spiciness}}

Section: Classes

Chapter #1 - The class directive

💾 Source Code

â„¢ Official Tutorial Page

Like any other attribute, you can specify classes with a JavaScript attribute, seen here:

<button
    class="{current === 'foo' ? 'selected' : ''}"
    on:click="{() => current = 'foo'}"
>foo</button>

This is such a common pattern in UI development that Svelte includes a special directive to simplify it:

<button
    class:selected="{current === 'foo'}"
    on:click="{() => current = 'foo'}"
>foo</button>

The selected class is added to the element whenever the value of the expression is truthy, and removed when it's falsy.

Chapter #2 - Shorthand class directive

💾 Source Code

â„¢ Official Tutorial Page

Often, the name of the class will be the same as the name of the value it depends on:

<div class:big={big}>
    <!-- ... -->
</div>

In those cases we can use a shorthand form:

<div class:big>
    <!-- ... -->
</div>

Section: Component composition

Chapter #1 - Slots

💾 Source Code

â„¢ Official Tutorial Page

Just like elements can have children...

<div>
    <p>I'm a child of the div</p>
</div>

...so can components. Before a component can accept children, though, it needs to know where to put them. We do this with the <slot> element. Put this inside Box.svelte:

<div class="box">
    <slot></slot>
</div>

You can now put things in the box:

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

Chapter #2 - Slot fallbacks

💾 Source Code

â„¢ Official Tutorial Page

A component can specify fallbacks for any slots that are left empty, by putting content inside the <slot> element:

<div class="box">
    <slot>
        <em>no content was provided</em>
    </slot>
</div>

We can now create instances of <Box> without any children:

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

<Box/>

Chapter #3 - Named slots

💾 Source Code

â„¢ Official Tutorial Page

The previous example contained a default slot, which renders the direct children of a component. Sometimes you will need more control over placement, such as with this <ContactCard>. In those cases, we can use named slots.

In ContactCard.svelte, add a name attribute to each slot:

<article class="contact-card">
    <h2>
        <slot name="name">
            <span class="missing">Unknown name</span>
        </slot>
    </h2>

    <div class="address">
        <slot name="address">
            <span class="missing">Unknown address</span>
        </slot>
    </div>

    <div class="email">
        <slot name="email">
            <span class="missing">Unknown email</span>
        </slot>
    </div>
</article>

Then, add elements with corresponding slot="..." attributes inside the <ContactCard> component:

<ContactCard>
    <span slot="name">
        P. Sherman
    </span>

    <span slot="address">
        42 Wallaby Way<br>
        Sydney
    </span>
</ContactCard>

Chapter #4 - Checking for slot content

💾 Source Code

â„¢ Official Tutorial Page

In some cases, you may want to control parts of your component based on whether the parent passes in content for a certain slot. Perhaps you have a wrapper around that slot, and you don't want to render it if the slot is empty. Or perhaps you'd like to apply a class only if the slot is present. You can do this by checking the properties of the special $slots variable.

$slots is an object whose keys are the names of the slots passed in by the parent component. If the parent leaves a slot empty, then $slots will not have an entry for that slot.

Notice that both instances of <Project> in this example render a container for comments and a notification dot, even though only one has comments. We want to use $slots to make sure we only render these elements when the parent <App> passes in content for the comments slot.

In Project.svelte, update the class:has-discussion directive on the <article>:

<article class:has-discussion={$slots.comments}>

Next, wrap the comments slot and its wrapping <div> in an if block that checks $slots:

{##if $slots.comments}
    <div class="discussion">
        <h3>Comments</h3>
        <slot name="comments"></slot>
    </div>
{/if}

Now the comments container and the notification dot won't render when <App> leaves the comments slot empty.

Chapter #5 - Slot props

💾 Source Code

â„¢ Official Tutorial Page

In this app, we have a <Hoverable> component that tracks whether the mouse is currently over it. It needs to pass that data back to the parent component, so that we can update the slotted contents.

For this, we use slot props. In Hoverable.svelte, pass the hovering value into the slot:

<div on:mouseenter={enter} on:mouseleave={leave}>
    <slot hovering={hovering}></slot>
</div>

Remember you can also use the {hovering} shorthand, if you prefer.

Then, to expose hovering to the contents of the <Hoverable> component, we use the let directive:

<Hoverable let:hovering={hovering}>
    <div class:active={hovering}>
        {##if hovering}
            <p>I am being hovered upon.</p>
        {:else}
            <p>Hover over me!</p>
        {/if}
    </div>
</Hoverable>

You can rename the variable, if you want — let's call it active in the parent component:

<Hoverable let:hovering={active}>
    <div class:active>
        {##if active}
            <p>I am being hovered upon.</p>
        {:else}
            <p>Hover over me!</p>
        {/if}
    </div>
</Hoverable>

You can have as many of these components as you like, and the slotted props will remain local to the component where they're declared.

Named slots can also have props; use the let directive on an element with a slot="..." attribute, instead of on the component itself.

Section: Context API

Chapter #1 - setContext and getContext

💾 Source Code

â„¢ Official Tutorial Page

The context API provides a mechanism for components to 'talk' to each other without passing around data and functions as props, or dispatching lots of events. It's an advanced feature, but a useful one.

Take this example app using a Mapbox GL map. We'd like to display the markers, using the <MapMarker> component, but we don't want to have to pass around a reference to the underlying Mapbox instance as a prop on each component.

There are two halves to the context API — setContext and getContext. If a component calls setContext(key, context), then any child component can retrieve the context with const context = getContext(key).

Let's set the context first. In Map.svelte, import setContext from svelte and key from mapbox.js and call setContext:

import { onMount, setContext } from 'svelte';
import { mapbox, key } from './mapbox.js';

setContext(key, {
    getMap: () => map
});

The context object can be anything you like. Like lifecycle functions, setContext and getContext must be called during component initialisation. Calling it afterwards - for example inside onMount - will throw an error. In this example, since map isn't created until the component has mounted, our context object contains a getMap function rather than map itself.

On the other side of the equation, in MapMarker.svelte, we can now get a reference to the Mapbox instance:

import { getContext } from 'svelte';
import { mapbox, key } from './mapbox.js';

const { getMap } = getContext(key);
const map = getMap();

The markers can now add themselves to the map.

A more finished version of <MapMarker> would also handle removal and prop changes, but we're only demonstrating context here.

Context keys

In mapbox.js you'll see this line:

const key = {};

We can use anything as a key — we could do setContext('mapbox', ...) for example. The downside of using a string is that different component libraries might accidentally use the same one; using an object literal means the keys are guaranteed not to conflict in any circumstance (since an object only has referential equality to itself, i.e. {} !== {} whereas "x" === "x"), even when you have multiple different contexts operating across many component layers.

Contexts vs. stores

Contexts and stores seem similar. They differ in that stores are available to any part of an app, while a context is only available to a component and its descendants. This can be helpful if you want to use several instances of a component without the state of one interfering with the state of the others.

In fact, you might use the two together. Since context is not reactive, values that change over time should be represented as stores:

const { these, are, stores } = getContext(...);

Section: Special elements

Chapter #1 - svelte:self

💾 Source Code

â„¢ Official Tutorial Page

Svelte provides a variety of built-in elements. The first, <svelte:self>, allows a component to contain itself recursively.

It's useful for things like this folder tree view, where folders can contain other folders. In Folder.svelte we want to be able to do this...

{##if file.files}
    <Folder {...file}/>
{:else}
    <File {...file}/>
{/if}

...but that's impossible, because a module can't import itself. Instead, we use <svelte:self>:

{##if file.files}
    <svelte:self {...file}/>
{:else}
    <File {...file}/>
{/if}

Chapter #2 - svelte:component

💾 Source Code

â„¢ Official Tutorial Page

A component can change its category altogether with <svelte:component>. Instead of a sequence of if blocks...

{##if selected.color === 'red'}
    <RedThing/>
{:else if selected.color === 'green'}
    <GreenThing/>
{:else if selected.color === 'blue'}
    <BlueThing/>
{/if}

...we can have a single dynamic component:

<svelte:component this={selected.component}/>

The this value can be any component constructor, or a falsy value — if it's falsy, no component is rendered.

Chapter #3 - svelte:window

💾 Source Code

â„¢ Official Tutorial Page

Just as you can add event listeners to any DOM element, you can add event listeners to the window object with <svelte:window>.

On line 11, add the keydown listener:

<svelte:window on:keydown={handleKeydown}/>

As with DOM elements, you can add event modifiers like preventDefault.

Chapter #4 - svelte:window bindings

💾 Source Code

â„¢ Official Tutorial Page

We can also bind to certain properties of window, such as scrollY. Update line 7:

<svelte:window bind:scrollY={y}/>

The list of properties you can bind to is as follows:

All except scrollX and scrollY are readonly.

Chapter #5 - svelte:body

💾 Source Code

â„¢ Official Tutorial Page

Similar to <svelte:window>, the <svelte:body> element allows you to listen for events that fire on document.body. This is useful with the mouseenter and mouseleave events, which don't fire on window.

Add the mouseenter and mouseleave handlers to the <svelte:body> tag:

<svelte:body
    on:mouseenter={handleMouseenter}
    on:mouseleave={handleMouseleave}
/>

Chapter #6 - svelte:head

💾 Source Code

â„¢ Official Tutorial Page

The <svelte:head> element allows you to insert elements inside the <head> of your document:

<svelte:head>
    <link rel="stylesheet" href="tutorial/dark-theme.css">
</svelte:head>

In server-side rendering (SSR) mode, contents of <svelte:head> are returned separately from the rest of your HTML.

Chapter #7 - svelte:options

💾 Source Code

â„¢ Official Tutorial Page

The <svelte:options> element allows you to specify compiler options.

We'll use the immutable option as an example. In this app, the <Todo> component flashes whenever it receives new data. Clicking on one of the items toggles its done state by creating an updated todos array. This causes the other <Todo> items to flash, even though they don't end up making any changes to the DOM.

We can optimise this by telling the <Todo> component to expect immutable data. This means that we're promising never to mutate the todo prop, but will instead create new todo objects whenever things change.

Add this to the top of the Todo.svelte file:

<svelte:options immutable={true}/>

You can shorten this to <svelte:options immutable/> if you prefer.

Now, when you toggle todos by clicking on them, only the updated component flashes.

The options that can be set here are:

Consult the API reference for more information on these options.

Chapter #8 - svelte:fragment

💾 Source Code

â„¢ Official Tutorial Page

The <svelte:fragment> element allows you to place content in a named slot without wrapping it in a container DOM element. This keeps the flow layout of your document intact.

In the example notice how we applied a flex layout with a gap of 1em to the box.

<!-- Box.svelte -->
<div class="box">
    <slot name="header">No header was provided</slot>
    <p>Some content between header and footer</p>
    <slot name="footer"></slot>
</div>

<style>
    .box {        
        display: flex;
        flex-direction: column;
        gap: 1em;
    }
</style>

However, the content in the footer is not spaced out according to this rhythm because wrapping it in a div created a new flow layout.

We can solve this by changing <div slot="footer"> in the App component. Replace the <div> with <svelte:fragment>:

<svelte:fragment slot="footer">
    <p>All rights reserved.</p>
    <p>Copyright (c) 2019 Svelte Industries</p>
</svelte:fragment>

Section: Module context

Chapter #1 - Sharing code

💾 Source Code

â„¢ Official Tutorial Page

In all the examples we've seen so far, the <script> block contains code that runs when each component instance is initialised. For the vast majority of components, that's all you'll ever need.

Very occasionally, you'll need to run some code outside of an individual component instance. For example, you can play all five of these audio players simultaneously; it would be better if playing one stopped all the others.

We can do that by declaring a <script context="module"> block. Code contained inside it will run once, when the module first evaluates, rather than when a component is instantiated. Place this at the top of AudioPlayer.svelte:

<script context="module">
    let current;
</script>

It's now possible for the components to 'talk' to each other without any state management:

function stopOthers() {
    if (current && current !== audio) current.pause();
    current = audio;
}

Chapter #2 - Exports

💾 Source Code

â„¢ Official Tutorial Page

Anything exported from a context="module" script block becomes an export from the module itself. If we export a stopAll function from AudioPlayer.svelte...

<script context="module">
    const elements = new Set();

    export function stopAll() {
        elements.forEach(element => {
            element.pause();
        });
    }
</script>

...we can then import it from App.svelte...

<script>
    import AudioPlayer, { stopAll } from './AudioPlayer.svelte';
</script>

...and use it in an event handler:

<button on:click={stopAll}>
    stop all audio
</button>

You can't have a default export, because the component is the default export.

Section: Debugging

Chapter #1 - The @debug tag

💾 Source Code

â„¢ Official Tutorial Page

Occasionally, it's useful to inspect a piece of data as it flows through your app.

One approach is to use console.log(...) inside your markup. If you want to pause execution, though, you can use the {@debug ...} tag with a comma-separated list of values you want to inspect:

{@debug user}

<h1>Hello {user.firstname}!</h1>

If you now open your devtools and start interacting with the <input> elements, you'll trigger the debugger as the value of user changes.

Section: Next steps

Chapter #1 - Congratulations!

💾 Source Code

â„¢ Official Tutorial Page

You've now finished the Svelte tutorial and are ready to start building apps. You can refer back to individual chapters at any time (click the title above to reveal a dropdown) or continue your learning via the API reference, Examples and Blog. If you're a Twitter user, you can get updates via @sveltejs.

To get set up in your local development environment, check out the quickstart guide.

If you're looking for a more expansive framework that includes routing, server-side rendering and everything else, take a look at SvelteKit.

Most importantly: since you're now a member of the Svelte community, you should join our friendly Discord chatroom. That's where you'll find fellow Svelte users, and it's where we plan the future of the framework.