Working with Svelte stores - Learn web development

Working with Svelte stores
==========================

* Previous
* Overview: Client-side JavaScript frameworks
* Next

In the last article we completed the development of our app, finished organizing it into components, and discussed some advanced techniques for dealing with reactivity, working with DOM nodes, and exposing component functionality. In this article we will show another way to handle state management in Svelte: Stores. Stores are global data repositories that hold values. Components can subscribe to stores and receive notifications when their values change.

|  |  |
| --- | --- |
| Prerequisites: |
 At minimum, it is recommended that you are familiar with the core
 HTML,
 CSS, and
 JavaScript languages, and
 have knowledge of the
 terminal/command line.

 You'll need a terminal with node and npm installed to compile and build
 your app.
  |
| Objective: | Learn how to use Svelte stores |

Using stores we will create an `Alert` component that shows notifications on screen, which can receive messages from any component. In this case, the `Alert` component is independent of the rest — it is not a parent or child of any other — so the messages don't fit into the component hierarchy.

We will also see how to develop our own custom store to persist the todo information to web storage, allowing our to-dos to persist over page reloads.

Code along with us
------------------

### Git

Clone the GitHub repo (if you haven't already done it) with:

```bash
git clone https://github.com/opensas/mdn-svelte-tutorial.git
```

Then to get to the current app state, run

```bash
cd mdn-svelte-tutorial/06-stores
```

Or directly download the folder's content:

```bash
npx degit opensas/mdn-svelte-tutorial/06-stores
```

Remember to run `npm install && npm run dev` to start your app in development mode.

### REPL

To code along with us using the REPL, start at

https://svelte.dev/repl/d1fa84a5a4494366b179c87395940039?version=3.23.2

Dealing with our app state
--------------------------

We have already seen how our components can communicate with each other using props, two-way data binding, and events. In all these cases we were dealing with communication between parent and child components.

But not all application state belongs inside your application's component hierarchy. For example, information about the logged-in user, or whether the dark theme is selected or not.

Sometimes, your app state will need to be accessed by multiple components that are not hierarchically related, or by a regular JavaScript module.

Moreover, when your app becomes complicated and your component hierarchy gets complex, it might become too difficult for components to relay data between each other. In that case, moving to a global data store might be a good option. If you've already worked with Redux or Vuex, then you'll be familiar with how this kind of store works. Svelte stores offer similar features for state management.

A store is an object with a `subscribe()` method that allows interested parties to be notified whenever the store value changes and an optional `set()` method that allows you to set new values for the store. This minimal API is known as the store contract.

Svelte provides functions for creating readable, writable, and derived stores in the `svelte/store` module.

Svelte also provides a very intuitive way to integrate stores into its reactivity system using the reactive `$store` syntax. If you create your own stores honoring the store contract, you get this reactivity syntactic sugar for free.

Creating the Alert component
----------------------------

To show how to work with stores, we will create an `Alert` component. These kinds of widgets might also be known as popup notifications, toast, or notification bubbles.

Our `Alert` component will be displayed by the `App` component, but any component can send notifications to it. Whenever a notification arrives, the `Alert` component will be in charge of displaying it on screen.

### Creating a store

Let's start by creating a writable store. Any component will be able to write to this store, and the `Alert` component will subscribe to it and display a message whenever the store is modified.

1. Create a new file, `stores.js`, inside your `src` directory.
2. Give it the following content:

```js
import { writable } from "svelte/store";

export const alert = writable("Welcome to the to-do list app!");
```

**Note:** Stores can be defined and used outside Svelte components, so you can organize them in any way you please.

In the above code we import the `writable()` function from `svelte/store` and use it to create a new store called `alert` with an initial value of "Welcome to the to-do list app!". We then `export` the store.

### Creating the actual component

Let's now create our `Alert` component and see how we can read values from the store.

1. Create another new file named `src/components/Alert.svelte`.
2. Give it the following content:

```svelte
<script>
 import { alert } from '../stores.js'
 import { onDestroy } from 'svelte'

 let alertContent = ''

 const unsubscribe = alert.subscribe((value) => alertContent = value)

 onDestroy(unsubscribe)
</script>

{#if alertContent}
<div on:click={() => alertContent = ''}>
  <p>{ alertContent }</p>
</div>
{/if}

<style>
div {
 position: fixed;
 cursor: pointer;
 margin-right: 1.5rem;
 margin-left: 1.5rem;
 margin-top: 1rem;
 right: 0;
 display: flex;
 align-items: center;
 border-radius: 0.2rem;
 background-color: #565656;
 color: #fff;
 font-weight: 700;
 padding: 0.5rem 1.4rem;
 font-size: 1.5rem;
 z-index: 100;
 opacity: 95%;
}
div p {
 color: #fff;
}
div svg {
 height: 1.6rem;
 fill: currentcolor;
 width: 1.4rem;
 margin-right: 0.5rem;
}
</style>
```

Let's walk through this piece of code in detail.

* At the beginning we import the `alert` store.
* Next we import the `onDestroy()` lifecycle function, which lets us execute a callback after the component has been unmounted.
* We then create a local variable named `alertContent`. Remember that we can access top-level variables from the markup, and whenever they are modified, the DOM will update accordingly.
* Then we call the method `alert.subscribe()`, passing it a callback function as a parameter. Whenever the value of the store changes, the callback function will be called with the new value as its parameter. In the callback function we just assign the value we receive to the local variable, which will trigger the update of the component's DOM.
* The `subscribe()` method also returns a cleanup function, which takes care of releasing the subscription. So we subscribe when the component is being initialized, and use `onDestroy` to unsubscribe when the component is unmounted.
* Finally we use the `alertContent` variable in our markup, and if the user clicks on the alert we clean it.
* At the end we include a few CSS lines to style our `Alert` component.

This setup allows us to work with stores in a reactive way. When the value of the store changes, the callback is executed. There we assign a new value to a local variable, and thanks to Svelte reactivity all our markup and reactive dependencies are updated accordingly.

### Using the component

Let's now use our component.

1. In `App.svelte` we'll import the component. Add the following import statement below the existing one:

```js
import Alert from "./components/Alert.svelte";
```

2. Then call the `Alert` component just above the `Todos` call, like this:

```svelte
<Alert />
<Todos {todos} />
```

3. Load your test app now, and you should now see the `Alert` message on screen. You can click on it to dismiss it.

 ![A simple notification in the top right-hand corner of an app saying welcome to the to-do list app](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores/01-alert-message.png)
Making stores reactive with the reactive `$store` syntax
--------------------------------------------------------

This works, but you'll have to copy and paste all this code every time you want to subscribe to a store:

```svelte
<script>
 import myStore from "./stores.js";
 import { onDestroy } from "svelte";

 let myStoreContent = "";

 const unsubscribe = myStore.subscribe((value) => (myStoreContent = value));

 onDestroy(unsubscribe);
</script>

{myStoreContent}
```

That's too much boilerplate for Svelte! Being a compiler, Svelte has more resources to make our lives easier. In this case Svelte provides the reactive `$store` syntax, also known as auto-subscription. In simple terms, you just prefix the store with the `$` sign and Svelte will generate the code to make it reactive automatically. So our previous code block can be replaced with this:

```svelte
<script>
 import myStore from "./stores.js";
</script>

{$myStore}
```

And `$myStore` will be fully reactive. This also applies to your own custom stores. If you implement the `subscribe()` and `set()` methods, as we'll do later, the reactive `$store` syntax will also apply to your stores.

1. Let's apply this to our `Alert` component. Update the `<script>` and markup sections of `Alert.svelte` as follows:

```svelte
<script>
 import { alert } from '../stores.js'
</script>

{#if $alert}
<div on:click={() => $alert = ''}>
  <p>{ $alert }</p>
</div>
{/if}
```

2. Check your app again and you'll see that this works just like before. That's much better!

Behind the scenes Svelte has generated the code to declare the local variable `$alert`, subscribe to the `alert` store, update `$alert` whenever the store's content is modified, and unsubscribe when the component is unmounted. It will also generate the `alert.set()` statements whenever we assign a value to `$alert`.

The end result of this nifty trick is that you can access global stores just as easily as using reactive local variables.

This is a perfect example of how Svelte puts the compiler in charge of better developer ergonomics, not only saving us from typing boilerplate, but also generating less error-prone code.

Writing to our store
--------------------

Writing to our store is just a matter of importing it and executing `$store = 'new value'`. Let's use it in our `Todos` component.

1. Add the following `import` statement below the existing ones:

```js
import { alert } from "../stores.js";
```

2. Update your `addTodo()` function like so:

```js
function addTodo(name) {
  todos = [...todos, { id: newTodoId, name, completed: false }];
  $alert = `Todo '${name}' has been added`;
}
```

3. Update `removeTodo()` like so:

```js
function removeTodo(todo) {
  todos = todos.filter((t) => t.id !== todo.id);
  todosStatus.focus(); // give focus to status heading
  $alert = `Todo '${todo.name}' has been deleted`;
}
```

4. Update the `updateTodo()` function to this:

```js
function updateTodo(todo) {
  const i = todos.findIndex((t) => t.id === todo.id);
  if (todos[i].name !== todo.name)
    $alert = `todo '${todos[i].name}' has been renamed to '${todo.name}'`;
  if (todos[i].completed !== todo.completed)
    $alert = `todo '${todos[i].name}' marked as ${
 todo.completed ? "completed" : "active"
 }`;
  todos[i] = { ...todos[i], ...todo };
}
```

5. Add the following reactive block beneath the block that starts with `let filter = 'all'`:

```js
$: {
  if (filter === "all") {
    $alert = "Browsing all to-dos";
  } else if (filter === "active") {
    $alert = "Browsing active to-dos";
  } else if (filter === "completed") {
    $alert = "Browsing completed to-dos";
  }
}
```

6. And finally for now, update the `const checkAllTodos` and `const removeCompletedTodos` blocks as follows:

```js
const checkAllTodos = (completed) => {
  todos = todos.map((t) => ({ ...t, completed }));
  $alert = `${completed ? "Checked" : "Unchecked"} ${todos.length} to-dos`;
};
const removeCompletedTodos = () => {
  $alert = `Removed ${todos.filter((t) => t.completed).length} to-dos`;
  todos = todos.filter((t) => !t.completed);
};
```

7. So basically, we've imported the store and updated it on every event, which causes a new alert to show each time. Have a look at your app again, and try adding/deleting/updating a few to-dos!

As soon as we execute `$alert = …`, Svelte will run `alert.set()`. Our `Alert` component — like every subscriber to the alert store — will be notified when it receives a new value, and thanks to Svelte reactivity its markup will be updated.

We could do the same within any component or `.js` file.

**Note:** Outside Svelte components you cannot use the `$store` syntax. That's because the Svelte compiler won't touch anything outside Svelte components. In that case you'll have to rely on the `store.subscribe()` and `store.set()` methods.

Improving our Alert component
-----------------------------

It's a bit annoying having to click on the alert to get rid of it. It would be better if the notification just disappeared after a couple of seconds.

Let's see how to do that. We'll specify a prop with the milliseconds to wait before clearing the notification, and we'll define a timeout to remove the alert. We'll also take care of clearing the timeout when the `Alert` component is unmounted to prevent memory leaks.

1. Update the `<script>` section of your `Alert.svelte` component like so:

```js
import { onDestroy } from "svelte";
import { alert } from "../stores.js";

export let ms = 3000;
let visible;
let timeout;

const onMessageChange = (message, ms) => {
  clearTimeout(timeout);
  if (!message) {
    // hide Alert if message is empty
    visible = false;
  } else {
    visible = true; // show alert
    if (ms > 0) timeout = setTimeout(() => (visible = false), ms); // and hide it after ms milliseconds
  }
};
$: onMessageChange($alert, ms); // whenever the alert store or the ms props changes run onMessageChange

onDestroy(() => clearTimeout(timeout)); // make sure we clean-up the timeout
```

2. And update the `Alert.svelte` markup section like so:

```svelte
{#if visible}
<div on:click={() => visible = false}>
  <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path d="M12.432 0c1.34 0 2.01.912 2.01 1.957 0 1.305-1.164 2.512-2.679 2.512-1.269 0-2.009-.75-1.974-1.99C9.789 1.436 10.67 0 12.432 0zM8.309 20c-1.058 0-1.833-.652-1.093-3.524l1.214-5.092c.211-.814.246-1.141 0-1.141-.317 0-1.689.562-2.502 1.117l-.528-.88c2.572-2.186 5.531-3.467 6.801-3.467 1.057 0 1.233 1.273.705 3.23l-1.391 5.352c-.246.945-.141 1.271.106 1.271.317 0 1.357-.392 2.379-1.207l.6.814C12.098 19.02 9.365 20 8.309 20z"/></svg>
  <p>{ $alert }</p>
</div>
{/if}
```

Here we first create the prop `ms` with a default value of 3000 (milliseconds). Then we create an `onMessageChange()` function that will take care of controlling whether the Alert is visible or not. With `$: onMessageChange($alert, ms)` we tell Svelte to run this function whenever the `$alert` store or the `ms` prop changes.

Whenever the `$alert` store changes, we'll clean up any pending timeout. If `$alert` is empty, we set `visible` to `false` and the `Alert` will be removed from the DOM. If it is not empty, we set `visible` to `true` and use the `setTimeout()` function to clear the alert after `ms` milliseconds.

Finally, with the `onDestroy()` lifecycle function, we make sure to call the `clearTimeout()` function.

We also added an SVG icon above the alert paragraph, to make it look a bit nicer. Try it out again, and you should see the changes.

Making our Alert component accessible
-------------------------------------

Our `Alert` component is working fine, but it's not very friendly to assistive technologies. The problem is elements that are dynamically added and removed from the page. While visually evident to users who can see the page, they may not be so obvious to users of assistive technologies, like screen readers. To handle those situations, we can take advantage of ARIA live regions, which provide a way to programmatically expose dynamic content changes so that they can be detected and announced by assistive technologies.

We can declare a region that contains dynamic content that should be announced by assistive technologies with the `aria-live` property followed by the politeness setting, which is used to set the priority with which screen readers should handle updates to that regions. The possible settings are `off`, `polite`, or `assertive`.

For common situations, you also have several predefined specialized `role` values that can be used, like `log`, `status` and `alert`.

In our case, just adding a `role="alert"` to the `<div>` container will do the trick, like this:

```svelte
<div role="alert" on:click={() => visible = false}>
```

In general, testing your applications using screen readers is a good idea, not only to discover accessibility issues but also to get used to how visually impaired people use the Web. You have several options, like NVDA for Windows, ChromeVox for Chrome, Orca on Linux, and VoiceOver for macOS and iOS, among other options.

To learn more about detecting and fixing accessibility issues, check out our Handling common accessibility problems article.

Using the store contract to persist our to-dos
----------------------------------------------

Our little app lets us manage our to-dos quite easily, but is rather useless if we always get the same list of hardcoded to-dos when we reload it. To make it truly useful, we have to find out how to persist our to-dos.

First we need some way for our `Todos` component to give back the updated to-dos to its parent. We could emit an updated event with the list of to-dos, but it's easier just to bind the `todos` variable. Let's open `App.svelte` and try it.

1. First, add the following line below your `todos` array:

```js
$: console.log("todos", todos);
```

2. Next, update your `Todos` component call as follows:

```svelte
<Todos bind:todos />
```

**Note:** `<Todos bind:todos />` is just a shortcut for `<Todos bind:todos={todos} />`.
3. Go back to your app, try adding some to-dos, then go to your developer tools web console. You'll see that every modification we make to our to-dos is reflected in the `todos` array defined in `App.svelte` thanks to the `bind` directive.

 Now we have to find a way to persist these to-dos. We could implement some code in our `App.svelte` component to read and save our to-dos to web storage or to a web service.
 But wouldn't it be better if we could develop some generic store that allows us to persist its content? This would allow us to use it just like any other store, and abstract away the persistence mechanism. We could create a store that syncs its content to web storage, and later develop another one that syncs against a web service. Switching between them would be trivial and we wouldn't have to touch `App.svelte` at all.

### Saving our to-dos

So let's start by using a regular writable store to save our to-dos.

1. Open the file `stores.js` and add the following store below the existing one:

```js
export const todos = writable([]);
```

2. That was easy. Now we need to import the store and use it in `App.svelte`. Just remember that to access the to-dos now we have to use the `$todos` reactive `$store` syntax.
 Update your `App.svelte` file like this:

```svelte
<script>
 import Todos from "./components/Todos.svelte";
 import Alert from "./components/Alert.svelte";

 import { todos } from "./stores.js";

 $todos = [
 { id: 1, name: "Create a Svelte starter app", completed: true },
 { id: 2, name: "Create your first component", completed: true },
 { id: 3, name: "Complete the rest of the tutorial", completed: false }
 ];
</script>

<Alert />
<Todos bind:todos={$todos} />
```

3. Try it out; everything should work. Next we'll see how to define our own custom stores.
### How to implement a store contract: The theory

You can create your own stores without relying on `svelte/store` by implementing the store contract. Its features must work like so:

1. A store must contain a `subscribe()` method, which must accept as its argument a subscription function. All of a store's active subscription functions must be called whenever the store's value changes.
2. The `subscribe()` method must return an `unsubscribe()` function, which when called must stop its subscription.
3. A store may optionally contain a `set()` method, which must accept as its argument a new value for the store, and which synchronously calls all of the store's active subscription functions. A store with a `set()` method is called a writable store.

First, let's add the following `console.log()` statements to our `App.svelte` component to see the `todos` store and its content in action. Add these lines below the `todos` array:

```js
console.log("todos store - todos:", todos);
console.log("todos store content - $todos:", $todos);
```

When you run the app now, you'll see something like this in your web console:

![web console showing the functions and contents of the todos store](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores/02-svelte-store-in-action.png)

As you can see, our store is just an object containing `subscribe()`, `set()`, and `update()` methods, and `$todos` is our array of to-dos.

Just for reference, here's a basic working store implemented from scratch:

```js
export const writable = (initial\_value = 0) => {
  let value = initial_value; // content of the store
  let subs = []; // subscriber's handlers

  const subscribe = (handler) => {
    subs = [...subs, handler]; // add handler to the array of subscribers
    handler(value); // call handler with current value
    return () => (subs = subs.filter((sub) => sub !== handler)); // return unsubscribe function
  };

  const set = (new\_value) => {
    if (value === new_value) return; // same value, exit
    value = new_value; // update value
    subs.forEach((sub) => sub(value)); // update subscribers
  };

  const update = (update\_fn) => set(update\_fn(value)); // update function

  return { subscribe, set, update }; // store contract
};
```

Here we declare `subs`, which is an array of subscribers. In the `subscribe()` method we add the handler to the `subs` array and return a function that, when executed, will remove the handler from the array.

When we call `set()`, we update the value of the store and call each handler, passing the new value as a parameter.

Usually you don't implement stores from scratch; instead you'd use the writable store to create custom stores with domain-specific logic. In the following example we create a counter store, which will only allow us to add one to the counter or reset its value:

```js
import { writable } from "svelte/store";
function myStore() {
  const { subscribe, set, update } = writable(0);

  return {
    subscribe,
    addOne: () => update((n) => n + 1),
    reset: () => set(0),
  };
}
```

If our to-do list app gets too complex, we could let our to-dos store handle every state modification. We could move all the methods that modify the `todo` array (like `addTodo()`, `removeTodo()`, etc.) from our `Todos` component to the store. If you have a central place where all the state modification is applied, components could just call those methods to modify the app's state and reactively display the info exposed by the store. Having a unique place to handle state modifications makes it easier to reason about the state flow and spot issues.

Svelte won't force you to organize your state management in a specific way; it just provides the tools for you to choose how to handle it.

### Implementing our custom to-dos store

Our to-do list app is not particularly complex, so we won't move all our modification methods into a central place. We'll just leave them as they are, and instead concentrate on persisting our to-dos.

**Note:** If you are following this guide working from the Svelte REPL, you won't be able to complete this step. For security reasons the Svelte REPL works in a sandboxed environment which will not let you access web storage, and you will get a "The operation is insecure" error. In order to follow this section, you'll have to clone the repo and go to the `mdn-svelte-tutorial/06-stores` folder, or you can directly download the folder's content with `npx degit opensas/mdn-svelte-tutorial/06-stores`.

To implement a custom store that saves its content to web storage, we will need a writable store that does the following:

* Initially reads the value from web storage, and if it's not present, initializes it with a default value
* Whenever the value is modified, updates the store itself and also the data in local storage

Moreover, because web storage only supports saving string values, we will have to convert from object to string when saving, and vice versa when we are loading the value from local storage.

1. Create a new file called `localStore.js`, in your `src` directory.
2. Give it the following content:

```js
import { writable } from "svelte/store";

export const localStore = (key, initial) => {
  // receives the key of the local storage and an initial value

  const toString = (value) => JSON.stringify(value, null, 2); // helper function
  const toObj = JSON.parse; // helper function

  if (localStorage.getItem(key) === null) {
    // item not present in local storage
    localStorage.setItem(key, toString(initial)); // initialize local storage with initial value
  }

  const saved = toObj(localStorage.getItem(key)); // convert to object

  const { subscribe, set, update } = writable(saved); // create the underlying writable store

  return {
    subscribe,
    set: (value) => {
      localStorage.setItem(key, toString(value)); // save also to local storage as a string
      return set(value);
    },
    update,
  };
};
```

    * Our `localStore` will be a function that when executed initially reads its content from web storage, and returns an object with three methods: `subscribe()`, `set()`, and `update()`.
    * When we create a new `localStore`, we'll have to specify the key of the web storage and an initial value. We then check if the value exists in web storage and, if not, we create it.
    * We use the `localStorage.getItem(key)` and `localStorage.setItem(key, value)` methods to read and write information to web storage, and the `toString()` and `toObj()` (which uses `JSON.parse()`) helper functions to convert the values.
    * Next, we convert the string content received from the web storage to an object, and save that object in our store.
    * Finally, every time we update the contents of the store, we also update the web storage, with the value converted to a string.Notice that we only had to redefine the `set()` method, adding the operation to save the value to web storage. The rest of the code is mostly initializing and converting stuff.
3. Now we will use our local store from `stores.js` to create our locally persisted to-dos store.
 Update `stores.js` like so:

```js
import { writable } from "svelte/store";
import { localStore } from "./localStore.js";

export const alert = writable("Welcome to the to-do list app!");

const initialTodos = [
  { id: 1, name: "Visit MDN web docs", completed: true },
  { id: 2, name: "Complete the Svelte Tutorial", completed: false },
];

export const todos = localStore("mdn-svelte-todo", initialTodos);
```

Using `localStore('mdn-svelte-todo', initialTodos)`, we are configuring the store to save the data in web storage under the key `mdn-svelte-todo`. We also set a couple of todos as initial values.
4. Now let's get rid of the hardcoded to-dos in `App.svelte`. Update its contents as follows. We are basically just deleting the `$todos` array and the `console.log()` statements:

```svelte
<script>
 import Todos from './components/Todos.svelte'
 import Alert from './components/Alert.svelte'

 import { todos } from './stores.js'
</script>

<Alert />
<Todos bind:todos={$todos} />
```

**Note:** This is the only change we have to make in order to use our custom store. `App.svelte` is completely transparent in terms of what kind of store we are using.
5. Go ahead and try your app again. Create a few to-dos and then close the browser. You may even stop the Svelte server and restart it. Upon revisiting the URL, your to-dos will still be there.
6. You can also inspect it in the DevTools console. In the web console, enter the command `localStorage.getItem('mdn-svelte-todo')`. Make some changes to your app, like pressing the *Uncheck All* button, and check the web storage content once more. You will get something like this:

 ![to-do app with web console view alongside it, showing that when a to-do is changed in the app, the corresponding entry is changed in web storage](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_stores/03-persisting-todos-to-local-storage.png)

Svelte stores provide a very simple and lightweight, but extremely powerful, way to handle complex app state from a global data store in a reactive way. And because Svelte compiles our code, it can provide the `$store` auto-subscription syntax that allows us to work with stores in the same way as local variables. Because stores have a minimal API, it's very simple to create our custom stores to abstract away the inner workings of the store itself.

Bonus track: Transitions
------------------------

Let's change the subject now and do something fun and different: add an animation to our alerts. Svelte provides a whole module to define transitions and animations so we can make our user interfaces more appealing.

A transition is applied with the transition:fn directive, and is triggered by an element entering or leaving the DOM as a result of a state change. The `svelte/transition` module exports seven functions: `fade`, `blur`, `fly`, `slide`, `scale`, `draw`, and `crossfade`.

Let's give our `Alert` component a fly `transition`. We'll open the `Alert.svelte` file and import the `fly` function from the `svelte/transition` module.

1. Put the following `import` statement below the existing ones:

```js
import { fly } from "svelte/transition";
```

2. To use it, update your opening `<div>` tag like so:

```svelte
<div role="alert" on:click={() => visible = false}
 transition:fly
>
```

Transitions can also receive parameters, like this:

```svelte
<div role="alert" on:click={() => visible = false}
 transition:fly="{{delay: 250, duration: 300, x: 0, y: -100, opacity: 0.5}}"
>
```

**Note:** The double curly braces are not special Svelte syntax. It's just a literal JavaScript object being passed as a parameter to the fly transition.
3. Try your app out again, and you'll see that the notifications now look a bit more appealing.

**Note:** Being a compiler allows Svelte to optimize the size of our bundle by excluding features that are not used. In this case, if we compile our app for production with `npm run build`, our `public/build/bundle.js` file will weight a little less than 22 KB. If we remove the `transitions:fly` directive Svelte is smart enough to realize the fly function is not being used and the `bundle.js` file size will drop down to just 18 KB.

This is just the tip of the iceberg. Svelte has lots of options for dealing with animations and transitions. Svelte also supports specifying different transitions to apply when the element is added or removed from the DOM with the `in:fn`/`out:fn` directives, and it also allows you to define your custom CSS and JavaScript transitions. It also has several easing functions to specify the rate of change over time. Have a look at the ease visualizer to explore the various ease functions available.

The code so far
---------------

### Git

To see the state of the code as it should be at the end of this article, access your copy of our repo like this:

```bash
cd mdn-svelte-tutorial/07-next-steps
```

Or directly download the folder's content:

```bash
npx degit opensas/mdn-svelte-tutorial/07-next-steps
```

Remember to run `npm install && npm run dev` to start your app in development mode.

### REPL

To see the current state of the code in a REPL, visit:

https://svelte.dev/repl/378dd79e0dfe4486a8f10823f3813190?version=3.23.2

Summary
-------

In this article we added two new features: an `Alert` component and persisting `todos` to web storage.

* This allowed us to showcase some advanced Svelte techniques. We developed the `Alert` component to show how to implement cross-component state management using stores. We also saw how to auto-subscribe to stores to seamlessly integrate them with the Svelte reactivity system.
* Then we saw how to implement our own store from scratch, and also how to extend Svelte's writable store to persist data to web storage.
* At the end we had a look at using the Svelte `transition` directive to implement animations on DOM elements.

In the next article we will learn how add TypeScript support to our Svelte application. To take advantage of all its features, we will also port our entire application to TypeScript.

* Previous
* Overview: Client-side JavaScript frameworks
* Next


Beginning our Angular todo list app - Learn web development

Beginning our Angular todo list app
===================================

* Previous
* Overview: Client-side JavaScript frameworks
* Next

At this point, we are ready to start creating our to-do list application using Angular. The finished application will display a list of to-do items and includes editing, deleting, and adding features. In this article you will get to know your application structure, and work up to displaying a basic list of to-do items.

|  |  |
| --- | --- |
| Prerequisites: |
 Familiarity with the core HTML,
 CSS, and
 JavaScript languages,
 knowledge of the
 terminal/command line.
  |
| Objective: |
 To create our basic app structure, get it displaying a list of to-do
 items, and understand fundamental Angular concepts such as component
 structure, sharing data between components, and looping content
 creation.
  |

The to-do application structure
-------------------------------

 Just like a basic application that doesn't use a framework, an Angular application has an `index.html`.
 Within the `<body>` tag of the `index.html`, Angular uses a special element — `<app-root>` — to insert your main component, which in turn includes other components you create.
 Generally, you don't need to touch the `index.html`, instead focusing your work within specialized areas of your application called components.

### Organize your application with components

 Components are a central building block of Angular applications.
 This to-do application has two components — a component as a foundation for your application, and a component for handling to-do items.

 Each component is made up of a TypeScript class, HTML, and CSS.
 TypeScript transpiles, or converts, into JavaScript, which means that your application ultimately ends up in plain JavaScript but you have the convenience of using Typescript's extended features and streamlined syntax.

### Dynamically change the UI with \*ngIf and \*ngFor

 This tutorial also covers two important Angular directives for dynamically altering the structure of the DOM.
 A directive is like a command that you can use in your HTML to affect change in your application.

 The first directive that this tutorial covers is Angular's iterator, `*ngFor`.
 `*ngFor` can dynamically create DOM elements based on items in an array.

 The second directive that you learn in this tutorial is `*ngIf`.
 You can use `*ngIf` to add or remove elements from the DOM based on a condition.
 For example, if users want to edit an item in the to-do list, you can provide them with the means to edit the item.
 If they do not want to edit an item, you can remove the interface for editing.

### Share data between components

 In this to-do application, you configure your components to share data.
 To add new items to the to do list, the main component has to send the new item to the second component.
 This second component manages the items and takes care of editing, marking as done, and deleting individual items.

 You accomplish sharing data between Angular components with special decorators called `@Input()` and `@Output()`.
 You use these decorators to specify that certain properties allow data to go into or out of a component.
 To use `@Output()`, you raise an event in one component so that the other component knows that there is data available.

Define Item
-----------

In the `app` directory, create a new file named `item.ts` with the following contents:

```ts
export interface Item {
  description: string;
  done: boolean;
}
```

You won't use this file until later, but it is a good time to know and record your knowledge of what an `item` is. The `Item` interface creates an `item` object model so that your application will understand what an `item` is. For this to-do list, an `item` is an object that has a description and can be done.

Add logic to AppComponent
-------------------------

 Now that you know what an `item` is, you can give your application some items by adding them to the TypeScript file, `app.component.ts`.
 In `app.component.ts`, replace the contents with the following:

```js
import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html",
  styleUrls: ["./app.component.css"],
})
export class AppComponent {
  title = "todo";

  filter: "all" | "active" | "done" = "all";

  allItems = [
    { description: "eat", done: true },
    { description: "sleep", done: false },
    { description: "play", done: false },
    { description: "laugh", done: false },
  ];

  get items() {
    if (this.filter === "all") {
      return this.allItems;
    }
    return this.allItems.filter((item) =>
      this.filter === "done" ? item.done : !item.done
    );
  }
}
```

 The first line is a JavaScript import that imports Angular.
 The `@Component()` decorator specifies metadata about the `AppComponent`.
 The default metadata properties are as follows:

* `selector`: Tells you the name of the CSS selector that you use in a template to instantiate this component. Here it is `'app-root'`.
 In the `index.html`, within the `body` tag, the Angular CLI added `<app-root></app-root>` when generating your application.
 You use all component selectors in the same way by adding them to other component HTML templates.
* `templateUrl`: Specifies the HTML file to associate with this component.
 Here it is, './app.component.html',
* `styleUrls`: Provides the location and name of the file for your styles that apply specifically to this component. Here it is `'./app.component.css'`.

 The `filter` property is of type `union`, which means `filter` could have the value of `all`, `active`, or `done`.
 With the `union` type, if you make a typo in the value you assign to the `filter` property, TypeScript lets you know so that you can catch the bug early.
 This guide shows you how to add filtering in a later step, but you can also use a filter to show the default list of all the items.

 The `allItems` array contains the to-do items and whether they are `done`.
 The first item, `eat`, has a `done` value of true.

 The getter, `get items()`, retrieves the items from the `allItems` array if the `filter` is equal to `all`.
 Otherwise, `get items()` returns the `done` items or the outstanding items depending on how the user filters the view.
 The getter also establishes the name of the array as `items`, which you'll use in the next section.

Add HTML to the AppComponent template
-------------------------------------

To see the list of items in the browser, replace the contents of `app.component.html` with the following HTML:

```html
<div class="main">
  <h1>My To Do List</h1>
  <h2>What would you like to do today?</h2>

  <ul>
    <li \*ngFor="let item of items">{{item.description}}</li>
  </ul>
</div>
```

 The `<li>` contains an `*ngFor`, a built-in Angular directive that iterates over the items in the `items` array.
 For each item, `*ngFor` creates a new `<li>`.
 The double curly braces that contain `item.description` instructs Angular to populate each `<li>` with the text of each item's description.

In the browser, you should see the list of items as follows:
```

My To Do List
What would you like to do today?

* eat
* sleep
* play
* laugh
```

Add items to the list
---------------------

A to-do list needs a way to add items.

In `app.component.ts`, add the following method to the class:

```ts
addItem(description: string) {
  this.allItems.unshift({
    description,
    done: false
  });
}
```

 The `addItem()` method takes an item that the user provides and adds it to the array when the user clicks the **Add** button.
 The `addItem()` method uses the array method `unshift()` to add a new item to the beginning of the array and the top of the list.
 You could alternatively use `push()`, which would add the new item to the end of the array and the bottom of the list.

To use the `addItem()` method, edit the HTML in the `AppComponent` template.

In `app.component.html`, replace the `<h2>` with the following:

```html
<label for="addItemInput">What would you like to do today?</label>

<input
 #newItem
 placeholder="add an item"
 (keyup.enter)="addItem(newItem.value); newItem.value = ''"
 class="lg-text-input"
 id="addItemInput" />

<button class="btn-primary" (click)="addItem(newItem.value)">Add</button>
```

In the above HTML, `#newItem` is a template variable. The template variable in this case uses the `<input>` element as its value. Template variables can be referred to anywhere in the component's template.

 When the user types a new item in the `<input>` field and presses **Enter**, the `addItem()` method adds the value to the `allItems` array.
 Pressing the **Enter** key also resets the value of `<input>` to an empty string. The template variable `#newItem` is used to access the value of the `<input>` element in the template.
 Instead of pressing the **Enter** key, the user can also click the **Add** button, which calls the same `addItem()` method.

Summary
-------

By now you should have your basic list of to-dos displaying in your browser. That's great progress! Of course, we have a lot more to do. In the next article we will look at adding some styling to our application.

* Previous
* Overview: Client-side JavaScript frameworks
* Next


Accessibility in React - Learn web development

Accessibility in React
======================

* Previous
* Overview: Client-side JavaScript frameworks
* Next

In our final tutorial article, we'll focus on (pun intended) accessibility, including focus management in React, which can improve usability and reduce confusion for both keyboard-only and screen reader users.

|  |  |
| --- | --- |
| Prerequisites: |
 Familiarity with the core HTML,
 CSS, and
 JavaScript languages,
 knowledge of the
 terminal/command line.
  |
| Objective: | To learn about implementing keyboard accessibility in React. |

Including keyboard users
------------------------

At this point, we've implemented all the features we set out to implement. Users can add a new task, check and uncheck tasks, delete tasks, or edit task names. Also, they can filter their task list by all, active, or completed tasks.

Or, at least, they can do all of these things with a mouse. Unfortunately, these features are not very accessible to keyboard-only users. Let's explore this now.

Exploring the keyboard usability problem
----------------------------------------

Start by clicking on the input at the top of our app, as if you're going to add a new task. You'll see a thick, dashed outline around that input. This outline is your visual indicator that the browser is currently focused on this element. Press the `Tab` key, and you will see the outline appear around the "Add" button beneath the input. This shows you that the browser's focus has moved.

Press `Tab` a few more times, and you will see this dashed focus indicator move between each of the filter buttons. Keep going until the focus indicator is around the first "Edit" button. Press `Enter`.

The `<Todo />` component will switch templates, as we designed, and you'll see a form that lets us edit the name of the task.

But where did our focus indicator go?

When we switch between templates in our `<Todo />` component, we completely remove the elements from the old template and replace them with the elements from the new template. That means the element that we were focused on no longer exists, so there's no visual cue as to where the browser's focus is. This could confuse a wide variety of users — particularly users who rely on the keyboard, or users who use assistive technology.

To improve the experience for keyboard and assistive technology users, we should manage the browser's focus ourselves.

### Aside: a note on our focus indicator

If you click the "All", "Active", or "Completed" filter buttons with your mouse, you *won't* see a visible focus indicator, but you will do if you move between them with the `Tab` key on your keyboard. Don't worry — your code isn't broken!

Our CSS file uses the `:focus-visible` pseudo-class to provide custom styling for the focus indicator, and the browser uses a set of internal rules to determine when to show it to the user. Generally, the browser *will* show a focus indicator in response to keyboard input, and *might* show it in response to mouse input. `<button>` elements *don't* show a focus indicator in response to mouse input, while `<input>` elements *do*.

The behavior of `:focus-visible` is more selective than the older `:focus` pseudo-class, with which you might be more familiar. `:focus` shows a focus indicator in many more situations, and you can use it instead of or in combination with `:focus-visible` if you prefer.

Focusing between templates
--------------------------

When a user changes the `<Todo />` template from viewing to editing, we should focus on the `<input>` used to rename it; when they change back from editing to viewing, we should move focus back to the "Edit" button.

### Targeting our elements

Up to this point, we've been writing JSX components and letting React build the resulting DOM behind the scenes. Most of the time, we don't need to target specific elements in the DOM because we can use React's state and props to control what gets rendered. To manage focus, however, we *do* need to be able to target specific DOM elements.

This is where the `useRef()` hook comes in.

First, change the `import` statement at the top of `Todo.jsx` so that it includes `useRef`:

```jsx
import { useRef, useState } from "react";
```

`useRef()` creates an object with a single property: `current`. Refs can store any values we want them to, and we can look up those values later. We can even store references to DOM elements, which is exactly what we're going to do here.

Next, create two new constants beneath the `useState()` hooks in your `Todo()` function. Each should be a ref – one for the "Edit" button in the view template and one for the edit field in the editing template.

```jsx
const editFieldRef = useRef(null);
const editButtonRef = useRef(null);
```

These refs have a default value of `null` to make it clear that they'll be empty until they're attached to their DOM elements. To attach them to their elements, we'll add the special `ref` attribute to each element's JSX, and set the values of those attributes to the appropriately named `ref` objects.

Update the `<input>` in your editing template so that it reads like this:

```jsx
<input
 id={props.id}
 className="todo-text"
 type="text"
 value={newName}
 onChange={handleChange}
 ref={editFieldRef}
/>
```

Update the "Edit" button in your view template so that it reads like this:

```jsx
<button
 type="button"
 className="btn"
 onClick={() => setEditing(true)}
 ref={editButtonRef}>
 Edit <span className="visually-hidden">{props.name}</span>
</button>
```

Doing this will populate our `editFieldRef` and `editButtonRef` with references to the DOM elements they're attached to, but *only* after React has rendered the component. Test that out for yourself: add the following line somewhere in the body of your `Todo()` function, below where `editButtonRef` is initialized:

```jsx
console.log(editButtonRef.current);
```

You'll see that the value of `editButtonRef.current` is `null` when the component first renders, but if you click an "Edit" button, it will log the `<input>` element to the console. This is because the ref is populated only after the component renders, and clicking the "Edit" button causes the component to re-render. Be sure to delete this log before moving on.

**Note:** Your logs will appear 6 times because we have 3 instances of `<Todo />` in our app and React renders our components twice in development.

We're getting closer! To take advantage of our newly referenced elements, we need to use another React hook: `useEffect()`.

### Implementing `useEffect()`

`useEffect()` is so named because it runs any side-effects that we'd like to add to the render process but which can't be run inside the main function body. `useEffect()` runs right after a component renders, meaning the DOM elements we referenced in the previous section will be available for us to use.

Change the import statement of `Todo.jsx` again to add `useEffect`:

```jsx
import { useEffect, useRef, useState } from "react";
```

`useEffect()` takes a function as an argument; this function is executed *after* the component renders. To demonstrate this, put the following `useEffect()` call just above the `return` statement in the body of `Todo()`, and pass a function into it that logs the words "side effect" to your console:

```jsx
useEffect(() => {
  console.log("side effect");
});
```

To illustrate the difference between the main render process and code run inside `useEffect()`, add another log – put this one below the previous addition:

```jsx
console.log("main render");
```

Now, open the app in your browser. You should see both messages in your console, with each one repeating multiple times. Note how "main render" logged first, and "side effect" logged second, even though the "side effect" log appears first in the code.
```

main render                                     Todo.jsx
side effect                                     Todo.jsx
```

Again, the logs are ordered this way because code inside `useEffect()` runs *after* the component renders. This takes some getting used to, just keep it in mind as you move forward. For now, delete `console.log("main render")` and we'll move on to implementing our focus management.

### Focusing on our editing field

Now that we know our `useEffect()` hook works, we can manage focus with it. As a reminder, we want to focus on the editing field when we switch to the editing template.

Update your existing `useEffect()` hook so that it reads like this:

```jsx
useEffect(() => {
  if (isEditing) {
    editFieldRef.current.focus();
  }
}, [isEditing]);
```

These changes make it so that, if `isEditing` is true, React reads the current value of the `editFieldRef` and moves browser focus to it. We also pass an array into `useEffect()` as a second argument. This array is a list of values `useEffect()` should depend on. With these values included, `useEffect()` will only run when one of those values changes. We only want to change focus when the value of `isEditing` changes.

Try it now: use the `Tab` key to navigate to one of the "Edit" buttons, then press `Enter`. You should see the `<Todo />` component switch to its editing template, and the browser focus indicator should appear around the `<input>` element!

### Moving focus back to the edit button

At first glance, getting React to move focus back to our "Edit" button when the edit is saved or cancelled appears deceptively easy. Surely we could add a condition to our `useEffect` to focus on the edit button if `isEditing` is `false`? Let's try it now — update your `useEffect()` call like so:

```jsx
useEffect(() => {
  if (isEditing) {
    editFieldRef.current.focus();
  } else {
    editButtonRef.current.focus();
  }
}, [isEditing]);
```

This kind of works. If you use your keyboard to trigger the "Edit" button (remember: `Tab` to it and press `Enter`), you'll see that your focus moves between the Edit `<input>` and "Edit" button as you start and end an edit. However, you may have noticed a new problem — the "Edit" button in the final `<Todo />` component is focused immediately on page load before we even interact with the app!

Our `useEffect()` hook is behaving exactly as we designed it: it runs as soon as the component renders, sees that `isEditing` is `false`, and focuses the "Edit" button. There are three instances of `<Todo />`, and focus is given to the "Edit" button of the one that renders last.

We need to refactor our approach so that focus changes only when `isEditing` changes from one value to another.

More robust focus management
----------------------------

To meet our refined criteria, we need to know not just the value of `isEditing`, but also *when that value has changed*. To do that, we need to be able to read the previous value of the `isEditing` constant. Using pseudocode, our logic should be something like this:

```jsx
if (wasNotEditingBefore && isEditingNow) {
  focusOnEditField();
} else if (wasEditingBefore && isNotEditingNow) {
  focusOnEditButton();
}
```

The React team has discussed ways to get a component's previous state, and provided an example hook we can use for the job.

### Enter `usePrevious()`

Paste the following code near the top of `Todo.jsx`, above your `Todo()` function.

```jsx
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}
```

`usePrevious()` is a *custom hook* that tracks a value across renders. It:

1. Uses the `useRef()` hook to create an empty `ref`.
2. Returns the `ref`'s `current` value to the component that called it.
3. Calls `useEffect()` and updates the value stored in `ref.current` after each rendering of the calling component.

The behavior of `useEffect()` is key to this functionality. Because `ref.current` is updated inside a `useEffect()` call, it's always one step behind whatever value is in the component's main render cycle – hence the name `usePrevious()`.

### Using `usePrevious()`

Now we can define a `wasEditing` constant to track the previous value of `isEditing`; this is achieved by calling `usePrevious` with `isEditing` as an argument. Add the following inside `Todo()`, below the `useRef` lines:

```jsx
const wasEditing = usePrevious(isEditing);
```

You can see how `usePrevious()` behaves by adding a console log beneath this line:

```jsx
console.log(wasEditing);
```

In this log, the `current` value of `wasEditing` will always be the previous value of `isEditing`. Click on the "Edit" and "Cancel" button a few times to watch it change, then delete this log when you're ready to move on.

With this `wasEditing` constant, we can update our `useEffect()` hook to implement the pseudocode we discussed before:

```jsx
useEffect(() => {
  if (!wasEditing && isEditing) {
    editFieldRef.current.focus();
  } else if (wasEditing && !isEditing) {
    editButtonRef.current.focus();
  }
}, [wasEditing, isEditing]);
```

Note that the logic of `useEffect()` now depends on `wasEditing`, so we provide it in the array of dependencies.

Try using your keyboard to activate the "Edit" and "Cancel" buttons in the `<Todo />` component; you'll see the browser focus indicator move appropriately, without the problem we discussed at the start of this section.

Focusing when the user deletes a task
-------------------------------------

There's one last keyboard experience gap: when a user deletes a task from the list, the focus vanishes. We're going to follow a pattern similar to our previous changes: we'll make a new ref, and utilize our `usePrevious()` hook, so that we can focus on the list heading whenever a user deletes a task.

### Why the list heading?

Sometimes, the place we want to send our focus to is obvious: when we toggled our `<Todo />` templates, we had an origin point to "go back" to — the "Edit" button. In this case however, since we're completely removing elements from the DOM, we have no place to go back to. The next best thing is an intuitive location somewhere nearby. The list heading is our best choice because it's close to the list item the user will delete, and focusing on it will tell the user how many tasks are left.

### Creating our ref

Import the `useRef()` and `useEffect()` hooks into `App.jsx` — you'll need them both below:

```jsx
import { useState, useRef, useEffect } from "react";
```

Next, declare a new ref inside the `App()` function, just above the `return` statement:

```jsx
const listHeadingRef = useRef(null);
```

### Prepare the heading

Heading elements like our `<h2>` are not usually focusable. This isn't a problem — we can make any element programmatically focusable by adding the attribute `tabindex="-1"` to it. This means *only focusable with JavaScript*. You can't press `Tab` to focus on an element with a tabindex of `-1` the same way you could do with a `<button>` or `<a>` element (this can be done using `tabindex="0"`, but that's not appropriate in this case).

Let's add the `tabindex` attribute — written as `tabIndex` in JSX — to the heading above our list of tasks, along with our `listHeadingRef`:

```jsx
<h2 id="list-heading" tabIndex="-1" ref={listHeadingRef}>
 {headingText}
</h2>
```

**Note:** The `tabindex` attribute is excellent for accessibility edge cases, but you should take **great care** not to overuse it. Only apply a `tabindex` to an element when you're sure that making it focusable will benefit your user somehow. In most cases, you should utilize elements that can naturally take focus, such as buttons, anchors, and inputs. Irresponsible usage of `tabindex` could have a profoundly negative impact on keyboard and screen reader users!

### Getting previous state

We want to focus on the element associated with our ref (via the `ref` attribute) only when our user deletes a task from their list. That's going to require the `usePrevious()` hook we used earlier on. Add it to the top of your `App.jsx` file, just below the imports:

```jsx
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}
```

Now add the following, above the `return` statement inside the `App()` function:

```jsx
const prevTaskLength = usePrevious(tasks.length);
```

Here we are invoking `usePrevious()` to track the previous length of the tasks array.

**Note:** Since we're now utilizing `usePrevious()` in two files, it might be more efficient to move the `usePrevious()` function into its own file, export it from that file, and import it where you need it. Try doing this as an exercise once you've got to the end.

### Using `useEffect()` to control our heading focus

Now that we've stored how many tasks we previously had, we can set up a `useEffect()` hook to run when our number of tasks changes, which will focus the heading if the number of tasks we have now is less than it previously was — that is, we deleted a task!

Add the following into the body of your `App()` function, just below your previous additions:

```jsx
useEffect(() => {
  if (tasks.length < prevTaskLength) {
    listHeadingRef.current.focus();
  }
}, [tasks.length, prevTaskLength]);
```

We only try to focus on our list heading if we have fewer tasks now than we did before. The dependencies passed into this hook ensure it will only try to re-run when either of those values (the number of current tasks, or the number of previous tasks) changes.

Now, when you use your keyboard to delete a task in your browser, you will see our dashed focus outline appear around the heading above the list.

Finished!
---------

You've just finished building a React app from the ground up! Congratulations! The skills you've learned here will be a great foundation to build on as you continue working with React.

Most of the time, you can be an effective contributor to a React project even if all you do is think carefully about components and their state and props. Remember to always write the best HTML you can.

`useRef()` and `useEffect()` are somewhat advanced features, and you should be proud of yourself for using them! Look out for opportunities to practice them more, because doing so will allow you to create inclusive experiences for users. Remember: our app would have been inaccessible to keyboard users without them!

**Note:** If you need to check your code against our version, you can find a finished version of the sample React app code in our todo-react repository. For a running live version, see https://mdn.github.io/todo-react.

In the very last article we'll present you with a list of React resources that you can use to go further in your learning.

* Previous
* Overview: Client-side JavaScript frameworks
* Next


Styling Vue components with CSS - Learn web development

Styling Vue components with CSS
===============================

* Previous
* Overview: Client-side JavaScript frameworks
* Next

The time has finally come to make our app look a bit nicer. In this article we'll explore the different ways of styling Vue components with CSS.

|  |  |
| --- | --- |
| Prerequisites: |
 Familiarity with the core HTML,
 CSS, and
 JavaScript languages,
 knowledge of the
 terminal/command line.

 Vue components are written as a combination of JavaScript objects that
 manage the app's data and an HTML-based template syntax that maps to
 the underlying DOM structure. For installation, and to use some of the
 more advanced features of Vue (like Single File Components or render
 functions), you'll need a terminal with node + npm installed.
  |
| Objective: | To learn about styling Vue components. |

Styling Vue components with CSS
-------------------------------

Before we move on to add more advanced features to our app, we should add some basic CSS to make it look better. Vue has three common approaches to styling apps:

* External CSS files.
* Global styles in Single File Components (`.vue` files).
* Component-scoped styles in Single File Components.

To help familiarize you with each one, we'll use a combination of all three to give our app a nicer look and feel.

Styling with external CSS files
-------------------------------

You can include external CSS files and apply them globally to your app. Let's look at how this is done.

To start with, create a file called `reset.css` in the `src/assets` directory. Files in this folder get processed by Webpack. This means we can use CSS pre-processors (like SCSS) or post-processors (like PostCSS).

While this tutorial will not be using such tools, it's good to know that when including such code in the assets folder it will be processed automatically.

Add the following contents to the `reset.css` file:

```css
/\*reset.css\*/
/\* RESETS \*/
\*,
\*::before,
\*::after {
  box-sizing: border-box;
}
\*:focus {
  outline: 3px dashed #228bec;
}
html {
  font: 62.5% / 1.15 sans-serif;
}
h1,
h2 {
  margin-bottom: 0;
}
ul {
  list-style: none;
  padding: 0;
}
button {
  border: none;
  margin: 0;
  padding: 0;
  width: auto;
  overflow: visible;
  background: transparent;
  color: inherit;
  font: inherit;
  line-height: normal;
  -webkit-font-smoothing: inherit;
  -moz-osx-font-smoothing: inherit;
  appearance: none;
}
button::-moz-focus-inner {
  border: 0;
}
button,
input,
optgroup,
select,
textarea {
  font-family: inherit;
  font-size: 100%;
  line-height: 1.15;
  margin: 0;
}
button,
input {
  /\* 1 \*/
  overflow: visible;
}
input[type="text"] {
  border-radius: 0;
}
body {
  width: 100%;
  max-width: 68rem;
  margin: 0 auto;
  font:
    1.6rem/1.25 "Helvetica Neue",
    Helvetica,
    Arial,
    sans-serif;
  background-color: #f5f5f5;
  color: #4d4d4d;
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
}
@media screen and (min-width: 620px) {
  body {
    font-size: 1.9rem;
    line-height: 1.31579;
  }
}
/\*END RESETS\*/
```

Next, in your `src/main.js` file, import the `reset.css` file like so:

```js
import "./assets/reset.css";
```

This will cause the file to get picked up during the build step and automatically added to our site.

The reset styles should be applied to the app now. The images below show the look of the app before and after the reset is applied.

Before:

![the todo app with partial styling added; the app is now in a card, but some of the internal features still need styling](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling/todo-app-unstyled.png)

After:

![the todo app with partial styling added; the app is now in a card, but some of the internal features still need styling](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling/todo-app-reset-styles.png)

Noticeable changes include the removal of the list bullets, background color changes, and changes to the base button and input styles.

Adding global styles to Single File Components
----------------------------------------------

Now that we've reset our CSS to be uniform across browsers, we need to customize the styles a bit more. There are some styles that we want to apply across components in our app. While adding these files directly to the `reset.css` stylesheet would work, we'll instead add them to the `<style>` tags in `App.vue` to demonstrate how this can be used.

There are already some styles present in the file. Let's remove those and replace them with the styles below. These styles do a few things — adding some styling to buttons and inputs, and customizing the `#app` element and its children.

Update your `App.vue` file's `<style>` element so it looks like so:

```html
<style>
 /\* Global styles \*/
 .btn {
 padding: 0.8rem 1rem 0.7rem;
 border: 0.2rem solid #4d4d4d;
 cursor: pointer;
 text-transform: capitalize;
 }
 .btn\_\_danger {
 color: #fff;
 background-color: #ca3c3c;
 border-color: #bd2130;
 }
 .btn\_\_filter {
 border-color: lightgrey;
 }
 .btn\_\_danger:focus {
 outline-color: #c82333;
 }
 .btn\_\_primary {
 color: #fff;
 background-color: #000;
 }
 .btn-group {
 display: flex;
 justify-content: space-between;
 }
 .btn-group > \* {
 flex: 1 1 auto;
 }
 .btn-group > \* + \* {
 margin-left: 0.8rem;
 }
 .label-wrapper {
 margin: 0;
 flex: 0 0 100%;
 text-align: center;
 }
 [class\*="\_\_lg"] {
 display: inline-block;
 width: 100%;
 font-size: 1.9rem;
 }
 [class\*="\_\_lg"]:not(:last-child) {
 margin-bottom: 1rem;
 }
 @media screen and (min-width: 620px) {
 [class\*="\_\_lg"] {
 font-size: 2.4rem;
 }
 }
 .visually-hidden {
 position: absolute;
 height: 1px;
 width: 1px;
 overflow: hidden;
 clip: rect(1px 1px 1px 1px);
 clip: rect(1px, 1px, 1px, 1px);
 clip-path: rect(1px, 1px, 1px, 1px);
 white-space: nowrap;
 }
 [class\*="stack"] > \* {
 margin-top: 0;
 margin-bottom: 0;
 }
 .stack-small > \* + \* {
 margin-top: 1.25rem;
 }
 .stack-large > \* + \* {
 margin-top: 2.5rem;
 }
 @media screen and (min-width: 550px) {
 .stack-small > \* + \* {
 margin-top: 1.4rem;
 }
 .stack-large > \* + \* {
 margin-top: 2.8rem;
 }
 }
 /\* End global styles \*/
 #app {
 background: #fff;
 margin: 2rem 0 4rem 0;
 padding: 1rem;
 padding-top: 0;
 position: relative;
 box-shadow:
 0 2px 4px 0 rgb(0 0 0 / 20%),
 0 2.5rem 5rem 0 rgb(0 0 0 / 10%);
 }
 @media screen and (min-width: 550px) {
 #app {
 padding: 4rem;
 }
 }
 #app > \* {
 max-width: 50rem;
 margin-left: auto;
 margin-right: auto;
 }
 #app > form {
 max-width: 100%;
 }
 #app h1 {
 display: block;
 min-width: 100%;
 width: 100%;
 text-align: center;
 margin: 0;
 margin-bottom: 1rem;
 }
</style>
```

If you check the app, you'll see that our todo list is now in a card, and we have some better formatting of our to-do items. Now we can go through and begin editing our components to use some of these styles.

![the todo app with partial styling added; the app is now in a card, but some of the internal features still need styling](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling/todo-app-partial-styles.png)

### Adding CSS classes in Vue

We should apply the button CSS classes to the `<button>` in our `ToDoForm` component. Since Vue templates are valid HTML, this is done in the same way to how you might do it in plain HTML — by adding a `class=""` attribute to the element.

Add `class="btn btn__primary btn__lg"` to your form's `<button>` element:

```html
<button type="submit" class="btn btn\_\_primary btn\_\_lg">Add</button>
```

While we're here, there's one more semantic and styling change we can make. Since our form denotes a specific section of our page, it could benefit from an `<h2>` element. The label, however, already denotes the purpose of the form. To avoid repeating ourselves, let's wrap our label in an `<h2>`. There are a few other global CSS styles which we can add as well. We'll also add the `input__lg` class to our `<input>` element.

Update your `ToDoForm` template so that it looks like this:

```html
<template>
  <form @submit.prevent="onSubmit">
    <h2 class="label-wrapper">
      <label for="new-todo-input" class="label\_\_lg">
        What needs to be done?
      </label>
    </h2>
    <input
 type="text"
 id="new-todo-input"
 name="new-todo"
 autocomplete="off"
 v-model.lazy.trim="label"
 class="input\_\_lg" />
    <button type="submit" class="btn btn\_\_primary btn\_\_lg">Add</button>
  </form>
</template>
```

Let's also add the `stack-large` class to the `<ul>` tag in our `App.vue` file. This will help improve the spacing of our to-do items a bit.

Update it as follows:

```html
<ul aria-labelledby="list-summary" class="stack-large">
  …
</ul>
```

Adding scoped styles
--------------------

The last component we want to style is our `ToDoItem` component. To keep the style definitions close to the component we can add a `<style>` element inside it. However, if these styles alter things outside of this component, it could be challenging to track down the styles responsible, and fix the problem. This is where the `scoped` attribute can be useful — this attaches a unique HTML `data` attribute selector to all of your styles, preventing them from colliding globally.

To use the `scoped` modifier, create a `<style>` element inside `ToDoItem.vue`, at the bottom of the file, and give it a `scoped` attribute:

```html
<style scoped>
 /\* … \*/
</style>
```

Next, copy the following CSS into the newly created `<style>` element:

```css
.custom-checkbox > .checkbox-label {
  font-family: Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-weight: 400;
  font-size: 16px;
  font-size: 1rem;
  line-height: 1.25;
  color: #0b0c0c;
  display: block;
  margin-bottom: 5px;
}
.custom-checkbox > .checkbox {
  font-family: Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-weight: 400;
  font-size: 16px;
  font-size: 1rem;
  line-height: 1.25;
  box-sizing: border-box;
  width: 100%;
  height: 40px;
  height: 2.5rem;
  margin-top: 0;
  padding: 5px;
  border: 2px solid #0b0c0c;
  border-radius: 0;
  appearance: none;
}
.custom-checkbox > input:focus {
  outline: 3px dashed #fd0;
  outline-offset: 0;
  box-shadow: inset 0 0 0 2px;
}
.custom-checkbox {
  font-family: Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  font-weight: 400;
  font-size: 1.6rem;
  line-height: 1.25;
  display: block;
  position: relative;
  min-height: 40px;
  margin-bottom: 10px;
  padding-left: 40px;
  clear: left;
}
.custom-checkbox > input[type="checkbox"] {
  -webkit-font-smoothing: antialiased;
  cursor: pointer;
  position: absolute;
  z-index: 1;
  top: -2px;
  left: -2px;
  width: 44px;
  height: 44px;
  margin: 0;
  opacity: 0;
}
.custom-checkbox > .checkbox-label {
  font-size: inherit;
  font-family: inherit;
  line-height: inherit;
  display: inline-block;
  margin-bottom: 0;
  padding: 8px 15px 5px;
  cursor: pointer;
  touch-action: manipulation;
}
.custom-checkbox > label::before {
  content: "";
  box-sizing: border-box;
  position: absolute;
  top: 0;
  left: 0;
  width: 40px;
  height: 40px;
  border: 2px solid currentcolor;
  background: transparent;
}
.custom-checkbox > input[type="checkbox"]:focus + label::before {
  border-width: 4px;
  outline: 3px dashed #228bec;
}
.custom-checkbox > label::after {
  box-sizing: content-box;
  content: "";
  position: absolute;
  top: 11px;
  left: 9px;
  width: 18px;
  height: 7px;
  transform: rotate(-45deg);
  border: solid;
  border-width: 0 0 5px 5px;
  border-top-color: transparent;
  opacity: 0;
  background: transparent;
}
.custom-checkbox > input[type="checkbox"]:checked + label::after {
  opacity: 1;
}
@media only screen and (min-width: 40rem) {
  label,
 input,
 .custom-checkbox {
    font-size: 19px;
    font-size: 1.9rem;
    line-height: 1.31579;
  }
}
```

Now we need to add some CSS classes to our template to connect the styles.

To the root `<div>`, add a `custom-checkbox` class. To the `<input>`, add a `checkbox` class. Last of all, to the `<label>` add a `checkbox-label` class. The updated template is below:

```html
<template>
  <div class="custom-checkbox">
    <input type="checkbox" :id="id" :checked="isDone" class="checkbox" />
    <label :for="id" class="checkbox-label">{{label}}</label>
  </div>
</template>
```

The app should now have custom checkboxes. Your app should look something like the screenshot below.

![the todo app with complete styling. The input form is now styled properly, and the todo items now have spacing and custom checkboxes](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Vue_styling/todo-app-complete-styles.png)

Summary
-------

Our work is done on the styling of our sample app. In the next article we'll return to adding some more functionality to our app, namely using a computed property to add a count of completed todo items to our app.

* Previous
* Overview: Client-side JavaScript frameworks
* Next


Deployment and next steps - Learn web development

Deployment and next steps
=========================

* Previous
* Overview: Client-side JavaScript frameworks
* Next

In the previous article we learned about Svelte's TypeScript support, and how to use it to make your application more robust. In this final article we will look at how to deploy your application and get it online, and also share some of the resources that you should go on to, to continue your Svelte learning journey.

|  |  |
| --- | --- |
| Prerequisites: |
 At minimum, it is recommended that you are familiar with the core
 HTML,
 CSS, and
 JavaScript languages, and
 have knowledge of the
 terminal/command line.

 You'll need a terminal with node + npm installed to compile and build
 your app.
  |
| Objective: |
 Learn how to prepare our Svelte app for production, and what learning
 resources you should visit next.
  |

Code along with us
------------------

### Git

Clone the GitHub repo (if you haven't already done it) with:

```bash
git clone https://github.com/opensas/mdn-svelte-tutorial.git
```

Then to get to the current app state, run

```bash
cd mdn-svelte-tutorial/08-next-steps
```

Or directly download the folder's content:

```bash
npx degit opensas/mdn-svelte-tutorial/08-next-steps
```

Remember to run `npm install && npm run dev` to start your app in development mode.

Compiling our app
-----------------

So far we've been running our app in development mode with `npm run dev`. As we saw earlier, this instruction tells Svelte to compile our components and JavaScript files into a `public/build/bundle.js` file and all the CSS sections of our components into `public/build/bundle.css`. It also starts a development server and watches for changes, recompiling the app and refreshing the page when a change occurs.

Your generated `bundle.js` and `bundle.css` files will be something like this (file size on the left):
```

  504 Jul 13 02:43 bundle.css
95981 Jul 13 02:43 bundle.js
```

To compile our application for production we have to run `npm run build` instead. In this case, Svelte won't launch a web server or keep watching for changes. It will however minify and compress our JavaScript files using terser.

So, after running `npm run build`, our generated `bundle.js` and `bundle.css` files will be more like this:
```

  504 Jul 13 02:43 bundle.css
21782 Jul 13 02:43 bundle.js
```

Try running `npm run build` in your app's root directory now. You might get a warning, but you can ignore this for now.

Our whole app is now just 21 KB — 8.3 KB when gzipped. There are no additional runtimes or dependencies to download, parse, execute, and keep running in memory. Svelte analyzed our components and compiled the code to vanilla JavaScript.

A look behind the Svelte compilation process
--------------------------------------------

By default, when you create a new app with `npx degit sveltejs/template my-svelte-project`, Svelte will use rollup as the module bundler.

**Note:** There is also an official template for using webpack and also many community-maintained plugins for other bundlers.

In the file `package.json` you can see that the `build` and `dev` scripts are just calling rollup:

```json
"scripts": {
  "build": "rollup -c",
  "dev": "rollup -c -w",
  "start": "sirv public"
},
```

In the `dev` script we are passing the `-w` argument, which tells rollup to watch files and rebuild on changes.

If we have a look at the `rollup.config.js` file, we can see that the Svelte compiler is just a rollup plugin:

```js
import svelte from 'rollup-plugin-svelte';
// …
import { terser } from 'rollup-plugin-terser';

const production = !process.env.ROLLUP\_WATCH;

export default {
  input: 'src/main.js',
  output: {
    sourcemap: true,
    format: 'iife',
    name: 'app',
    file: 'public/build/bundle.js'
  },
  plugins: [
    svelte({
      // enable run-time checks when not in production
      dev: !production,
      // we'll extract any component CSS out into
      // a separate file - better for performance
      css: (css) => {
        css.write('public/build/bundle.css');
      }
    }),
```

Later on in the same file you'll also see how rollup minimizes our scripts in production mode and launches a local server in development mode:

```js
    // In dev mode, call `npm run start` once
    // the bundle has been generated
    !production && serve(),

    // Watch the `public` directory and refresh the
    // browser on changes when not in production
    !production && livereload('public'),

    // If we're building for production (npm run build
    // instead of npm run dev), minify
    production && terser()
  ],
```

There are many plugins for rollup that allow you to customize its behavior. A particularly useful plugin which is also maintained by the Svelte team is svelte-preprocess, which pre-processes many different languages in Svelte files such as PostCSS, SCSS, Less, CoffeeScript, SASS, and TypeScript.

Deploying your Svelte application
---------------------------------

From the point of view of a web server, a Svelte application is nothing more than a bunch of HTML, CSS, and JavaScript files. All you need is a web server capable of serving static files, which means you have plenty of options to choose from. Let's look at a couple of examples.

**Note:** the following section could be applied to any client-side static website requiring a build step, not just Svelte apps.

### Deploying with Vercel

One of the easiest ways to deploy a Svelte application is using Vercel. Vercel is a cloud platform specifically tailored for static sites, which has out-of-the-box support for most common front-end tools, Svelte being one of them.

To deploy our app, follow these steps.

1. register for an account with Vercel.
2. Navigate to the root of your app and run `npx vercel`; the first time you do it, you'll be prompted to enter your email address, and follow the steps in the email sent to that address, for security purposes.
3. Run `npx vercel` again, and you'll be prompted to answer a few questions, like this:

```bash
npx vercel
```

```
Vercel CLI 19.1.2
? Set up and deploy "./mdn-svelte-tutorial"? [Y/n] y
? Which scope do you want to deploy to? opensas
? Link to existing project? [y/N] n
? What's your project's name? mdn-svelte-tutorial
? In which directory is your code located? ./
Auto-detected Project Settings (Svelte):
- Build Command: `npm run build` or `rollup -c`
- Output Directory: public
- Development Command: sirv public --single --dev --port $PORT
? Want to override the settings? [y/N] n
   Linked to opensas/mdn-svelte-tutorial (created .vercel)
   Inspect: https://vercel.com/opensas/mdn-svelte-tutorial/[...] [1s]
✅  Production: https://mdn-svelte-tutorial.vercel.app [copied to clipboard] [19s]
   Deployed to production. Run `vercel --prod` to overwrite later (https://vercel.link/2F).
   To change the domain or build command, go to https://zeit.co/opensas/mdn-svelte-tutorial/settings
```

4. Accept all the defaults, and you'll be fine.
5. Once it has finished deploying, go to the "Production" URL in your browser, and you'll see the app deployed!

You can also import a Svelte git project into Vercel from GitHub, GitLab, or BitBucket.

**Note:** you can globally install Vercel with `npm i -g vercel` so you don't have to use `npx` to run it.

### Automatic deployment to GitLab pages

For hosting static files there are several online services that allow you to automatically deploy your site whenever you push changes to a git repository. Most of them involve setting up a deployment pipeline that gets triggered on every `git push`, and takes care of building and deploying your website.

To demonstrate this, we will deploy our todos app to GitLab Pages.

1. First you'll have to register at GitLab and then create a new project. Give you new project a short, easy name like "mdn-svelte-todo". You will have a remote URL that points to your new GitLab git repository, like `git@gitlab.com:[your-user]/[your-project].git`.
2. Before you start to upload content to your git repository, it is a good practice to add a `.gitignore` file to tell git which files to exclude from source control. In our case we will tell git to exclude files in the `node_modules` directory by creating a `.gitignore` file in the root folder of your local project, with the following content:

```bash
node_modules/
```

3. Now let's go back to GitLab. After creating a new repo GitLab will greet you with a message explaining different options to upload your existing files. Follow the steps listed under the *Push an existing folder* heading:

```bash
cd your_root_directory # Go into your project's root directory
git init
git remote add origin https://gitlab.com/[your-user]/mdn-svelte-todo.git
git add .
git commit -m "Initial commit"
git push -u origin main
```

**Note:** You could use the `git` protocol instead of `https`, which is faster and saves you from typing your username and password every time you access your origin repo. To use it you'll have to create an SSH key pair. Your origin URL will be like this: `git@gitlab.com:[your-user]/mdn-svelte-todo.git`.

With these instructions we initialize a local git repository, then set our remote origin (where we will push our code to) as our repo on GitLab. Next we commit all the files to the local git repo, and then push those to the remote origin on GitLab.

GitLab uses a built-in tool called GitLab CI/CD to build your site and publish it to the GitLab Pages server. The sequence of scripts that GitLab CI/CD runs to accomplish this task is created from a file named `.gitlab-ci.yml`, which you can create and modify at will. A specific job called `pages` in the configuration file will make GitLab aware that you are deploying a GitLab Pages website.

Let's have a go at doing this now.

1. Create a `.gitlab-ci.yml` file inside your project's root and give it the following content:

```yaml
image: node:latest
pages:
  stage: deploy
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - public
  only:
    - main
```

Here we are telling GitLab to use an image with the latest version of node to build our app. Next we are declaring a `pages` job, to enable GitLab Pages. Whenever there's a push to our repo, GitLab will run `npm install` and `npm run build` to build our application. We are also telling GitLab to deploy the contents of the `public` folder. On the last line, we are configuring GitLab to redeploy our app only when there's a push to our main branch.
2. Since our app will be published at a subdirectory (like `https://your-user.gitlab.io/mdn-svelte-todo`), we'll have to make the references to the JavaScript and CSS files in our `public/index.html` file relative. To do this, we just remove the leading slashes (`/`) from the `/global.css`, `/build/bundle.css`, and `/build/bundle.js` URLs, like this:

```html
<title>Svelte To-Do list</title>

<link rel="icon" type="image/png" href="favicon.png" />
<link rel="stylesheet" href="global.css" />
<link rel="stylesheet" href="build/bundle.css" />

<script defer src="build/bundle.js"></script>
```

Do this now.
3. Now we just have to commit and push our changes to GitLab. Do this by running the following commands:

```bash
git add public/index.html
git add .gitlab-ci.yml
git commit -m "Added .gitlab-ci.yml file and fixed index.html absolute paths"
git push
```

Whenever there's a job running GitLab will display an icon showing the process of the job. Clicking on it will let you inspect the output of the job.

![gitlab screenshot showing a deployed commit, which add a gitlab ci file, and changes bundle paths to relative](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_deployment_next/01-gitlab-pages-deploy.png)

You can also check the progress of the current and previous jobs from the *CI / CD* > *Jobs* menu option of your GitLab project.

![a gitlab ci job shown in the gitlab ui, running a lot of commands](/en-US/docs/Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_deployment_next/02-gitlab-pages-job.png)

Once GitLab finishes building and publishing your app, it will be accessible at `https://your-user.gitlab.io/mdn-svelte-todo/`; in my case it's `https://opensas.gitlab.io/mdn-svelte-todo/`. You can check your page's URL in GitLab's UI — see the *Settings* > *Pages* menu option.

With this configuration, whenever you push changes to the GitLab repo, the application will be automatically rebuilt and deployed to GitLab Pages.

Learning more about Svelte
--------------------------

In this section we'll give you some resources and projects to go and check out, to take your Svelte learning further.

### Svelte documentation

To go further and learn more about Svelte, you should definitely visit the Svelte homepage. There you'll find many articles explaining Svelte's philosophy. If you haven't already done it, make sure you go through the Svelte interactive tutorial. We already covered most of its content, so it won't take you much time to complete it — you should consider it as practice!

You can also consult the Svelte API docs and the available examples.

To understand the motivations behind Svelte, you should read Rich Harris's Rethinking reactivity presentation on YouTube. He is the creator of Svelte, so he has a couple of things to say about it. You also have the interactive slides available here which are, unsurprisingly, built with Svelte. If you liked it, you will also enjoy The Return of 'Write Less, Do More' presentation, which Rich Harris gave at JSCAMP 2019.

### Related projects

There are other projects related to Svelte that are worth checking out:

* Sapper: An application framework powered by Svelte that provides server-side rendering (SSR), code splitting, file-based routing and offline support, and more. Think of it as Next.js for Svelte. If you are planning to develop a fairly complex web application you should definitely have a look at this project.
* Svelte Native: A mobile application framework powered by Svelte. Think of it as React Native for Svelte.
* Svelte for VS Code: The officially supported VS Code plugin for working with `.svelte` files, which we looked at in our TypeScript article.
### Other learning resources

* There's a complete course about Svelte and Sapper by Rich Harris, available at Frontend Masters.
* Even though Svelte is a relatively young project there are lots of tutorials and courses available on the web, so it's difficult to make a recommendation.
* Nevertheless, Svelte.js — The Complete Guide by Academind is a very popular option with great ratings.
* The Svelte Handbook, by Flavio Copes, is also a useful reference for learning the main Svelte concepts.
* If you prefer to read books, there's Svelte and Sapper in Action by Mark Volkman, expected to be published in September 2020, but which you can already preview online for free.
* If you want dive deeper and understand the inner working of Svelte's compiler you should check Tan Li Hau's *Compile Svelte in your head* blog posts. Here's Part 1, Part 2, and Part 3.
### Interacting with the community

There are a number of different ways to get support and interact with the Svelte community:

* svelte.dev/chat: Svelte's Discord server.
* @sveltejs: The official Twitter account.
* @sveltesociety: Svelte community Twitter account.
* Svelte Recipes: Community-driven repository of recipes, tips, and best practices to solve common problems.
* Svelte questions on StackOverflow: Questions with the `svelte` tag at SO.
* Svelte reddit community: Svelte community discussion and content rating site at reddit.
* Svelte DEV community: A collection of Svelte-related technical articles and tutorials from the DEV.to community.
Finito
------

Congratulations! You have completed the Svelte tutorial. In the previous articles we went from zero knowledge about Svelte to building and deploying a complete application.

* We learned about Svelte philosophy and what sets it apart from other front-end frameworks.
* We saw how to add dynamic behavior to our website, how to organize our app in components and different ways to share information among them.
* We took advantage of the Svelte reactivity system and learned how to avoid common pitfalls.
* We also saw some advanced concepts and techniques to interact with DOM elements and to programmatically extend HTML element capabilities using the `use` directive.
* Then we saw how to use stores to work with a central data repository, and we created our own custom store to persist our application's data to Web Storage.
* We also took a look at Svelte's TypeScript support.

In this article we've learned about a couple of zero-fuss options to deploy our app in production and seen how to set up a basic pipeline to deploy our app to GitLab on every commit. Then we provided you with a list of Svelte resources to go further with your Svelte learning.

Congratulations! After completing this series of tutorials you should have a strong base from which to start developing professional web applications with Svelte.

* Previous
* Overview: Client-side JavaScript frameworks
* Next