Skip to content

Svelte 5 Quickstart

This tutorial assumes you’re already familiar with HTML, CSS, and JS. It also assumes you know what a JS framework is for.

If you prefer to work online, you can open the Svelte training ground repo on Stackblitz and start coding right away in your browser. You don’t have to run any of the npm commands if you use Stackblitz.

If you prefer to work locally, you can follow these steps (you will need Node and npm installed).

First, visit the Svelte 5 training ground repo. Press the green Code button and click Download ZIP. Unzip the file and then open it in your editor. Then, run this command in the terminal to install the packages listed in package.json.

Terminal window
npm install

Then run this command to start the dev server.

Terminal window
npm run dev

You should see something like this in your terminal.

Terminal window
VITE v6.3.5 ready in 312 ms
Local: http://localhost:5173/
Network: use --host to expose
press h + enter to show help

Visit localhost:5173 in your browser. The web page should say Hello World.

In your editor, you’ll see several files. However, for now you’ll mainly be working in HelloWorld.svelte.

The simplest Svelte component you can have is an empty file.

In our file, we have an <h1> element already added.

HelloWorld.svelte
<h1>Hello World</h1>

Task: To make it more personal, change World to your name.

HelloWorld.svelte
<h1>Hello John</h1>

After saving, you should see the browser show your name.

Unlike some other JS frameworks, you can have more than one root element.

Task: Add a <p> element after the <h1> element with some placeholder text.

HelloWorld.svelte
<h1>Hello John</h1>
<p>Lorem ipsum dolor...</p>

After saving, you should now see both elements in the browser.

Before we look at our next topic, open up App.svelte so you can see how it’s importing HelloWorld.svelte. All you have to do is add an import statement inside the <script> element and then use the component as a tag in the HTML.

App.svelte
<script>
import HelloWorld from './lib/HelloWorld.svelte'
</script>
<HelloWorld />

You can add a style attribute to an element just like in normal HTML.

Task: Add style="color: red;" to the h1 element.

HelloWorld.svelte
<h1 style="color: red;">Hello World</h1>
<p>Lorem ipsum dolor...</p>

After saving, you should see the <h1> element turn red in the browser.

There is another syntax called the style: directive. You type style, then a colon, then the property name, then an equals sign, and finally the value in quotes. This is useful if you have a lot of inline styles.

HelloWorld.svelte
<h1 style:color = "red">Hello World</h1>
<p>Lorem ipsum dolor...</p>
References

You can also add a <style> element to style a component. The styles are limited to just the component by default.

Task: Delete the style attribute. Then add the <style> element with the following rule.

HelloWorld.svelte
<h1>Hello World</h1>
<p>Lorem ipsum dolor...</p>
<style>
h1 {
color: red;
}
</style>
References

You can use a class attribute just like in normal HTML.

Task: Add a class attribute with the value of heading. Change the h1 selector to .red.

HelloWorld.svelte
<h1 class="red">Hello World</h1>
<p>Lorem ipsum dolor...</p>
<style>
.red {
color: red;
}
</style>

After saving, you should see that the <h1> element is still red.

References

For this section, create a new file called Counter.svelte. Add the following code to it.

Counter.svelte
<button>Count: 0</button>

Next, make sure to import it into App.svelte.

App.svelte
<script>
import HelloWorld from './lib/HelloWorld.svelte';
import Counter from './lib/Counter.svelte';
</script>
<Counter />

After saving you should see the button appear on screen. It doesn’t do anything yet if you click on it.

Add a <script> element above the <button> element.

Counter.svelte
<script>
</script>
<button>Count: 0</button>

Svelte 5 uses runes to make things reactive.

Create a count variable and use the $state() rune to initialize it. Also, replace 0 with { count } in the <button> element. (To display a variable in Svelte, you wrap it in curly braces {}.)

Counter.svelte
<script>
let count = $state(0);
</script>
<button>Count: { count }</button>

After saving, the button should still look the same. It still doesn’t do anything yet.

Next, add onclick={ count++ } to the <button> tag.

Counter.svelte
<script>
let count = $state(0);
</script>
<button onclick={ count++ }>Count: { count }</button>

After saving, the number on the button will go up when you click on it.

The $state() rune makes count reactive, which means it will automatically update the UI when its value changes.

References

Create a function called increment(). Then replace count++ with increment.

Counter.svelte
<script>
let count = $state(0);
function increment() {
count++;
}
</script>
<button onclick={increment}>Count: { count }</button>

After saving, the number on the button should still go up when you click on it.

Let’s add a message that will display when you reach a certain count.

Task: Add an <h1> element using an if block. The <h1> will show when the count is greater than 10.

Counter.svelte
<script>
let count = $state(0);
function increment() {
count++;
}
</script>
{#if count > 10}
<h1>Good job!</h1>
{/if}
<button onclick={increment}>Count: { count }</button>

Now add an <h1> element with an else block. This <h1> will show when the count is 10 or less.

Counter.svelte
<script>
let count = $state(0);
function increment() {
count++;
}
</script>
{#if count > 10}
<h1>Good job!</h1>
{:else}
<h1>Let's get started</h1>
{/if}
<button onclick={increment}>Count: { count }</button>

Now add an <h1> with an else if block in the middle. This message will be displayed when count is greater than 5 but less than 11.

Counter.svelte
<script>
let count = $state(0);
function increment() {
count++;
}
</script>
{#if count > 10}
<h1>Good job!</h1>
{:else if count > 5}
<h1>Not bad</h1>
{:else}
<h1>Let's get started</h1>
{/if}
<button onclick={increment}>Count: { count }</button>
References

Let’s learn about binding. Binding is the technique that is used to keep the value of an input in sync with a reactive variable.

Let’s reset the Hello World component back to this.

HelloWorld.svelte
<h1>Hello World</h1>

Then, add the following code.

HelloWorld.svelte
<script>
let name = $state('');
</script>
<input bind:value={name} />
<h1>Hello {name}</h1>

The part that says bind:value={name} is how you bind the input to the name variable, which is reactive.

Now the heading will update whenever you type in the input.

References

Let’s create a new file called TodoList.svelte. Add the following code to it. This is the data we’re going to display.

Use an each block to loop through the todos array and display each todo item in a list. The part that says (todo.id) is a key that helps Svelte keep track of each item in the list.

TodoList.svelte
<script>
let id = 0;
let todos = $state([
{ id: id++, text: 'Learn HTML' },
{ id: id++, text: 'Learn JavaScript' },
{ id: id++, text: 'Learn Svelte' }
]);
</script>
<ul>
{#each todos as todo (todo.id)}
<li>{todo.text}</li>
{/each}
</ul>

Next, make sure to import it into App.svelte.

App.svelte
<script>
import HelloWorld from './lib/HelloWorld.svelte';
import Counter from './lib/Counter.svelte';
import TodoList from './lib/TodoList.svelte';
</script>
<TodoList />

You should now see a list in your browser.

References

To add items to the list, first create the newTodo variable in the <script> element. Then create the addTodo() function. Lastly, add the <input> and <button> elements to the HTML.

TodoList.svelte
<script>
let id = 0;
let newTodo = $state('');
let todos = $state([
{ id: id++, text: 'Learn HTML' },
{ id: id++, text: 'Learn JavaScript' },
{ id: id++, text: 'Learn Svelte' }
]);
function addTodo() {
todos.push({ id: id++, text: newTodo });
newTodo = '';
}
</script>
<input bind:value={newTodo} />
<button onclick={addTodo}>Add Todo</button>
<ul>
{#each todos as todo (todo.id)}
<li>{todo.text}</li>
{/each}
</ul>

You should now be able to add items to the list by typing in the input and clicking the button. The new items will appear at the end of the list.

To remove elements from the list, first add the removeTodo() function. Then add a <button> to each list item that calls the function with the todo’s id.

TodoList.svelte
15 collapsed lines
<script>
let id = 0;
let newTodo = $state('');
let todos = $state([
{ id: id++, text: 'Learn HTML' },
{ id: id++, text: 'Learn JavaScript' },
{ id: id++, text: 'Learn Svelte' }
]);
function addTodo() {
todos.push({ id: id++, text: newTodo });
newTodo = '';
}
function removeTodo(todoId) {
const idx = todos.findIndex(todo => todo.id === todoId);
if (idx !== -1) {
todos.splice(idx, 1);
}
}
</script>
<input bind:value={newTodo} />
<button onclick={addTodo}>Add Todo</button>
<ul>
{#each todos as todo (todo.id)}
<li>
{todo.text}
<button onclick={() => removeTodo(todo.id)}>X</button>
</li>
{/each}
</ul>

You should now be able to delete items from the list now by clicking the “X” button next to each item.

Let’s learn how to hide completed items. To do this, you need to use the $derived() rune. The $derived() rune allows you to create a variable that automatically updates when other variables update.

  1. Add a done property to each todo item.
  2. Add a hideCompleted variable that will be used to toggle the visibility of completed todos.
  3. Add a checkbox input to each todo item to mark it as done.
  4. Add a checkbox input to toggle the hideCompleted state.
  5. Add a visibleTodos variable that filters the todos based on the hideCompleted state.
  6. Don’t forget to change todos to visibleTodos inside the each block.
TodoList.svelte
<script>
let id = 0;
let newTodo = $state('');
let todos = $state([
{ id: id++, text: 'Learn HTML', done: false },
{ id: id++, text: 'Learn JavaScript', done: false },
{ id: id++, text: 'Learn Svelte', done: false }
]);
let hideCompleted = $state(false);
13 collapsed lines
function addTodo() {
todos.push({ id: id++, text: newTodo, done: false });
newTodo = '';
}
function removeTodo(todoId) {
const idx = todos.findIndex(todo => todo.id === todoId);
if (idx !== -1) {
todos.splice(idx, 1);
}
}
let visibleTodos = $derived(
hideCompleted
? todos.filter(todo => !todo.done)
: todos
);
</script>
<input bind:value={newTodo} />
<button onclick={addTodo}>Add Todo</button>
<label>
<input type="checkbox" bind:checked={hideCompleted} />
Hide completed
</label>
<ul>
{#each visibleTodos as todo (todo.id)}
<li>
<input type="checkbox" bind:checked={todo.done} />
<span>{todo.text}</span>
<button onclick={() => removeTodo(todo.id)}>X</button>
</li>
{/each}
</ul>

Notice that visibleTodos uses the $derived() rune. This means that it will automatically update whenever todos or hideCompleted changes.

References

Let’s learn how to make components more flexible using props. Props allow you to pass data from a parent component into a child component. Let’s revisit the HelloWorld.svelte component and make it accept a name prop. This way, we can pass different names to it. To do this, we need to use the $props() rune.

HelloWorld.svelte
<script>
let { name } = $props();
</script>
<h1>Hello { name }</h1>

Inside App.svelte, you can now pass a name prop to the HelloWorld component.

App.svelte
<script>
import HelloWorld from './lib/HelloWorld.svelte';
import Counter from './lib/Counter.svelte';
import TodoList from './lib/TodoList.svelte';
</script>
<HelloWorld name="John" />

The browser should now display the name you passed in.

References

Let’s learn how to toggle a class in Svelte. First, reset the Hello World component back to this:

HelloWorld.svelte
<h1 class="red">Hello World</h1>
<style>
.red {
color: red;
}
</style>

Create a <script> element and an isActive variable inside it. Then, use the $state() rune to initialize it to false. Add a ternary statement to the class attribute. Then add a <button> element with an onclick attribute.

HelloWorld.svelte
<script>
let isActive = $state(false);
</script>
<h1 class="{isActive ? 'red' : ''}">Hello World</h1>
<button
onclick={() => isActive = !isActive}
>
Toggle
</button>
<style>
.red {
color: red;
}
</style>

The text should now change colors when you click the button.

Svelte 5 was released in October 2024, so most LLMs do not know how to generate Svelte code with runes in it yet. One thing you can do to fix this is to download the llms-full.txt file for Svelte 5 and give it to the LLM you’re using. This file contains all of the Svelte 5 documentation. Tip: you should name the file svelte-5-docs.md so that the LLM can recognize it as Svelte 5 documentation.

As an example, we created a custom Svelte 5 GPT that you can try. It already has the llms-full.txt file loaded into it.

Here are the instructions we used to create it:

Answer questions about Svelte 5 and generate code using the attached svelte-5-docs.md file.