Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ You can build your entire app with Svelte (for example, using an application fra

## How to use this tutorial

> You'll need to have basic familiarity with HTML, CSS and JavaScript to understand Svelte.
> [!NOTE] You'll need to have basic familiarity with HTML, CSS and JavaScript to understand Svelte.

This tutorial is split into four main parts:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ Add a `<script>` tag to the top of `App.svelte` that imports `Nested.svelte`...

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

> Component names are capitalised, to distinguish them from HTML elements.
> [!NOTE] Component names are capitalised, to distinguish them from HTML elements.
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ In Svelte, you do this with the special `{@html ...}` tag:
<p>{+++@html+++ string}</p>
```

> **Warning!** Svelte doesn't perform any sanitization of the expression inside `{@html ...}` before it gets inserted into the DOM. This isn't an issue if the content is something you trust like an article you wrote yourself. However if it's some untrusted user content, e.g. a comment on an article, then it's critical that you manually escape it, otherwise you risk exposing your users to <a href="https://owasp.org/www-community/attacks/xss/" target="_blank">Cross-Site Scripting</a> (XSS) attacks.
> [!NOTE] Important: Svelte doesn't perform any sanitization of the expression inside `{@html ...}` before it gets inserted into the DOM. This isn't an issue if the content is something you trust like an article you wrote yourself. However if it's some untrusted user content, e.g. a comment on an article, then it's critical that you manually escape it, otherwise you risk exposing your users to <a href="https://owasp.org/www-community/attacks/xss/" target="_blank">Cross-Site Scripting</a> (XSS) attacks.
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ function addNumber() {
}
```

> Deep reactivity is implemented using [proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), and mutations to the proxy do not affect the original object.
> [!NOTE] Deep reactivity is implemented using [proxies](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy), and mutations to the proxy do not affect the original object.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ So far we've talked about reactivity in terms of state. But that's only half of

The thing that reacts is called an _effect_. You've already encountered effects — the ones that Svelte creates on your behalf to update the DOM in response to state changes — but you can also create your own with the `$effect` rune.

> Most of the time, you shouldn't. `$effect` is best thought of as an escape hatch, rather than something to use frequently. If you can put your side effects in an [event handler](dom-events), for example, that's almost always preferable.
> [!NOTE] Most of the time, you shouldn't. `$effect` is best thought of as an escape hatch, rather than something to use frequently. If you can put your side effects in an [event handler](dom-events), for example, that's almost always preferable.

Let's say we want to use `setInterval` to keep track of how long the component has been mounted. Create the effect:

Expand Down Expand Up @@ -45,4 +45,4 @@ The cleanup function is called immediately before the effect function re-runs wh

If the effect function doesn't read any state when it runs, it will only run once, when the component mounts.

> Effects do not run during server-side rendering.
> [!NOTE] Effects do not run during server-side rendering.
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ We _could_ fix it by adding the prop...
<PackageInfo +++{...pkg}+++ />
```

> Conversely, you can get an object containing all the props that were passed into a component using a rest property...
> [!NOTE] Conversely, you can get an object containing all the props that were passed into a component using a rest property...
>
> ```js
> let { name, ...stuff } = $props();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Instead of laboriously copying, pasting and editing, we can get rid of all but t
</div>
```

> The expression (`colors`, in this case) can be any iterable or array-like object — in other words, anything that works with [`Array.from`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from).
> [!NOTE] The expression (`colors`, in this case) can be any iterable or array-like object — in other words, anything that works with [`Array.from`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from).

Now we need to use the `color` variable in place of `"red"`:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Click the 'Remove first thing' button a few times, and notice what happens:
1. It removes the last component.
2. It then updates the `name` value in the remaining DOM nodes, but not the emoji.

> If you're coming from React, this might seem strange, because you're used to the entire component re-rendering when state changes. Svelte works differently: the component 'runs' once, and subsequent updates are 'fine-grained'. This makes things faster and gives you more control.
> [!NOTE] If you're coming from React, this might seem strange, because you're used to the entire component re-rendering when state changes. Svelte works differently: the component 'runs' once, and subsequent updates are 'fine-grained'. This makes things faster and gives you more control.

One way to fix it would be to make `emoji` a [`$derived`](derived-state) value. But it makes more sense to remove the first `<Thing>` component altogether than to remove the _last_ one and update all the others.

Expand All @@ -24,4 +24,4 @@ To do that, we specify a unique _key_ for each iteration of the `each` block:
{/each}
```

> 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.
> [!NOTE] 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.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Most web applications have to deal with asynchronous data at some point. Svelte
{/await}+++
```

> Only the most recent `promise` is considered, meaning you don't need to worry about race conditions.
> [!NOTE] 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:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ We can also use `bind:value` with `<select>` elements:

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.
> [!NOTE] 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.
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ Replace the checkboxes with a `<select multiple>`:

Note that we're able to omit the `value` attribute on the `<option>`, since the value is identical to the element's contents.

> Press and hold the `control` key (or the `command` key on MacOS) to select multiple options.
> [!NOTE] Press and hold the `control` key (or the `command` key on MacOS) to select multiple options.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Clicking the buttons causes the progress bar to animate to its new value. It's a
</script>
```

> The `svelte/easing` module contains the [Penner easing equations](https://web.archive.org/web/20190805215728/http://robertpenner.com/easing/), or you can supply your own `p => t` function where `p` and `t` are both values between 0 and 1.
> [!NOTE] The `svelte/easing` module contains the [Penner easing equations](https://web.archive.org/web/20190805215728/http://robertpenner.com/easing/), 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`:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ We can achieve this with a _global_ transition, which plays when _any_ block con
</div>
```

> In Svelte 3, transitions were global by default and you had to use the `|local` modifier to make them local.
> [!NOTE] In Svelte 3, transitions were global by default and you had to use the `|local` modifier to make them local.
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ The movement is a little slow in this case, so we can add a `duration` parameter
>
```

> `duration` can also be a `d => milliseconds` function, where `d` is the number of pixels the element has to travel
> [!NOTE] `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.
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ You can even bind to properties inside an `each` block.
{/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.
> [!NOTE] 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.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ Every block-level element has `clientWidth`, `clientHeight`, `offsetWidth` and `

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

> Elements are measured using a technique similar to [this one](http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/). There is some overhead involved, so it's not recommended to use this for large numbers of elements.
TODO this next thing is no longer true I think?

> [!NOTE] Elements are measured using a technique similar to [this one](http://www.backalleycoder.com/2013/03/18/cross-browser-event-based-element-resize-detection/). 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.
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ Just as you can bind to properties of DOM elements, you can bind to component pr

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'.
> [!NOTE] 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'.
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,4 @@ Finally, get rid of the placeholder variable, which we no longer need:
</script>
```

> Named slots can also have props; use the `let` directive on an element with a `slot="..."` attribute, instead of on the component itself.
> [!NOTE] Named slots can also have props; use the `let` directive on an element with a `slot="..."` attribute, instead of on the component itself.
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ Add the `selectionchange` handler to the `<svelte:document>` tag:
<svelte:document +++on:selectionchange={handleSelectionChange}+++ />
```

> Avoid `mouseenter` and `mouseleave` handlers on this element, as these events are not fired on `document` in all browsers. Use `<svelte:body>` instead.
> [!NOTE] Avoid `mouseenter` and `mouseleave` handlers on this element, as these events are not fired on `document` in all browsers. Use `<svelte:body>` instead.
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,4 @@ Since those are quite hard to show in the context of this tutorial, we'll use it
<h1>Welcome to my site!</h1>
```

> In server-side rendering (SSR) mode, contents of `<svelte:head>` are returned separately from the rest of your HTML.
> [!NOTE] In server-side rendering (SSR) mode, contents of `<svelte:head>` are returned separately from the rest of your HTML.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Add this to the top of `Todo.svelte`:
<svelte:options immutable={true} />
```

> You can shorten this to `<svelte:options immutable/>` if you prefer.
> [!NOTE] 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.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ We can now import `stopAll` in `App.svelte`...
</div>
```

> You can't have a default export, because the component _is_ the default export.
> [!NOTE] You can't have a default export, because the component _is_ the default export.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ On the right, in the file tree viewer, you'll see a handful of files that Svelte

`package.json` will be familiar if you've worked with Node.js before. It lists the project's dependencies — including `svelte` and `@sveltejs/kit` — and a variety of `scripts` for interacting with the SvelteKit CLI. (We're currently running `npm run dev` in the bottom window.)

> Note that it also specifies `"type": "module"`, which means that `.js` files are treated as native JavaScript modules by default, rather than the legacy CommonJS format.
> [!NOTE] Note that it also specifies `"type": "module"`, which means that `.js` files are treated as native JavaScript modules by default, rather than the legacy CommonJS format.

`svelte.config.js` contains your project configuration. We don't need to worry about this file for now, but if you're curious, [visit the documentation](https://kit.svelte.dev/docs/configuration).

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ Let's fix that. Add a second page, `src/routes/about/+page.svelte`, copy the con

We can now navigate between `/` and `/about`.

> Unlike traditional multi-page apps, navigating to `/about` and back updates the contents of the current page, like a single-page app. This gives us the best of both worlds — fast server-rendered startup, then instant navigation. (This behaviour can be [configured](https://kit.svelte.dev/docs/page-options).)
> [!NOTE] Unlike traditional multi-page apps, navigating to `/about` and back updates the contents of the current page, like a single-page app. This gives us the best of both worlds — fast server-rendered startup, then instant navigation. (This behaviour can be [configured](https://kit.svelte.dev/docs/page-options).)
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@ Let's create that file:

We can now navigate from the `/blog` page to individual blog posts. In the next chapter, we'll see how to load their content.

> Multiple route parameters can appear _within_ one URL segment, as long as they are separated by at least one static character: `foo/[bar]x[baz]` is a valid route where `[bar]` and `[baz]` are dynamic parameters.
> [!NOTE] Multiple route parameters can appear _within_ one URL segment, as long as they are separated by at least one static character: `foo/[bar]x[baz]` is a valid route where `[bar]` and `[baz]` are dynamic parameters.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export function load() {
}
```

> For the sake of the tutorial, we're importing data from `src/routes/blog/data.js`. In a real app, you'd be more likely to load the data from a database or a CMS, but for now we'll do it like this.
> [!NOTE] For the sake of the tutorial, we're importing data from `src/routes/blog/data.js`. In a real app, you'd be more likely to load the data from a database or a CMS, but for now we'll do it like this.

We can access this data in `src/routes/blog/+page.svelte` via the `data` prop:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const actions = {
};
```

> Default actions cannot coexist with named actions.
> [!NOTE] Default actions cannot coexist with named actions.

The `<form>` element has an optional `action` attribute, which is similar to an `<a>` element's `href` attribute. Update the existing form so that it points to the new `create` action:

Expand All @@ -38,7 +38,7 @@ The `<form>` element has an optional `action` attribute, which is similar to an
</form>
```

> The `action` attribute can be any URL — if the action was defined on another page, you might have something like `/todos?/create`. Since the action is on _this_ page, we can omit the pathname altogether, hence the leading `?` character.
> [!NOTE] The `action` attribute can be any URL — if the action was defined on another page, you might have something like `/todos?/create`. Since the action is on _this_ page, we can omit the pathname altogether, hence the leading `?` character.

Next, we want to create a form for each todo, complete with a hidden `<input>` that uniquely identifies it:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,4 @@ In `src/routes/+page.svelte`, we can access the returned value via the `form` pr
</form>
```

> You can also return data from an action _without_ wrapping it in `fail` — for example to show a 'success!' message when data was saved — and it will be available via the `form` prop.
> [!NOTE] You can also return data from an action _without_ wrapping it in `fail` — for example to show a 'success!' message when data was saved — and it will be available via the `form` prop.
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,4 @@ In the case of deletions, we don't really need to wait for the server to validat
</ul>
```

> `use:enhance` is very customizable — you can `cancel()` submissions, handle redirects, control whether the form is reset, and so on. [See the docs](https://kit.svelte.dev/docs/modules#$app-forms-enhance) for full details.
> [!NOTE] `use:enhance` is very customizable — you can `cancel()` submissions, handle redirects, control whether the form is reset, and so on. [See the docs](https://kit.svelte.dev/docs/modules#$app-forms-enhance) for full details.
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,4 @@ We're returning a response with a [201 Created](https://http.dog/201) status and
/>
```

> You should only mutate `data` in such a way that you'd get the same result by reloading the page.
> [!NOTE] You should only mutate `data` in such a way that you'd get the same result by reloading the page.
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ The `navigating` store represents the current navigation. When a navigation star
- `from` and `to` — objects with `params`, `route` and `url` properties
- `type` — the type of navigation, e.g. `link`, `popstate` or `goto`

> For complete type information visit the [`Navigation`](https://kit.svelte.dev/docs/types#public-types-navigation) documentation.
> [!NOTE] For complete type information visit the [`Navigation`](https://kit.svelte.dev/docs/types#public-types-navigation) documentation.

It can be used to show a loading indicator for long-running navigations. In this exercise, `src/routes/+page.server.js` and `src/routes/about/+page.server.js` both have an artificial delay. Inside `src/routes/+layout.svelte`, import the `navigating` store and add a message to the nav bar:

Expand Down
Loading
Loading