DEV Community

Cover image for Creating your first Svelte5 reactive component
Roberto B.
Roberto B.

Posted on • Edited on

Creating your first Svelte5 reactive component

Welcome to the exciting era of Svelte 5!

After an intensive development period, Svelte 5 has officially launched, marking a significant milestone for the Svelte community. This latest stable release introduces a host of cutting-edge features and enhancements that developers can confidently use in production environments.

With the release of Svelte 5, the installer and other critical components have been fully refined and are now available, providing a streamlined setup process. This release signals a new chapter for Svelte, as developers can now take full advantage of its powerful, stable features to build performant and reactive web applications.

With this article, I'll guide you through the process of installing Svelte 5 on your local development environment and explore its powerful new features, including the revamped and more potent reactivity mechanism.

Install the Svelte 5 skeleton project

To set up a Svelte 5 project with SvelteKit, we’ll use the new sv Command Line Interface (CLI). With npx sv create (or bunx sv create), you can initialize a SvelteKit project with Svelte 5 fully integrated.

In previous versions, creating a Svelte project required the create svelte@latest command. However, with this release, Svelte 5 introduces sv, a CLI designed to simplify and streamline the setup process, allowing developers to explore Svelte 5's new capabilities effortlessly.

bunx sv create myapp-svelte5-sveltekit
cd myapp-svelte5-sveltekit
bun install
Enter fullscreen mode Exit fullscreen mode

If you prefer using npx instead of bunx, you can use the npx sv create command.

During the execution of bunx sv create, the command will ask you some questions. For now, you can answer in this way:

◇  Which template would you like?
│  SvelteKit minimal
│
◇  Add type checking with Typescript?
│  Yes, using Typescript syntax
│
◇  What would you like to add to your project?
│  prettier
│
◇  Which package manager do you want to install dependencies with?
│  bun
Enter fullscreen mode Exit fullscreen mode

The sv create command will create a new directory with a minimal SvelteKit application and install the needed dependencies.

cd myapp-svelte5-sveltekit
bun run dev -- --open
Enter fullscreen mode Exit fullscreen mode

If you run the command bun pm ls (or npm list if you prefer to use npm), you can check the dependencies versions (at the moment, it is svelte@5.1.2):

bun pm ls
/Users/roberto/test/myapp-svelte5-sveltekit node_modules (138)
├── @sveltejs/adapter-auto@3.3.0
├── @sveltejs/kit@2.7.2
├── @sveltejs/vite-plugin-svelte@4.0.0
├── prettier@3.3.3
├── prettier-plugin-svelte@3.2.7
├── svelte@5.1.2
├── svelte-check@4.0.5
├── typescript@5.6.3
└── vite@5.4.10 
Enter fullscreen mode Exit fullscreen mode

Now, if you run bun run dev, you can start using your new fresh Svelte 5 application, typically exposed by default at http://localhost:5173/ .

bun run dev -- --open
Enter fullscreen mode Exit fullscreen mode

Now, we are going to create a new component with some reactivity.

Roll the dice web application

I want to create a simple “Roll the Dice” web application.

The user can click a button to generate a random number (from 1 to 6) and update the text showing the result and the list of the previous rolls.
This example is elementary but helpful in walking through the basic stuff of Svelte 5, understanding the main differences with Svelte4, and looking at the new Svelte5 reactivity mechanism via runes.

So now let’s jump on the code 🚀.

Creating the component

I will create the roller.svelte component in the file src/lib/components/roller.svelte.

If you are on macOS or Linux in your terminal, in the project directory you can first create the components directory and then the needed file:

mkdir -p src/lib/components
touch src/lib/components/roller.svelte
Enter fullscreen mode Exit fullscreen mode

The component will contain two classical parts: the first one about the logic (the script section), and then the second one about the template (the HTML part).

The script section:

<script lang="ts">
let dice: number = $state(0);
let rolls: number[] = $state([]);
let average: number = $derived(rolls.reduce((t, n) => t + n, 0) / rolls.length);

function draw() {
    dice = Math.floor(Math.random() * Math.floor(5)) + 1;
    rolls.push(dice);
}
function reset() {
    dice = 0;
    rolls = [];
}
</script>
Enter fullscreen mode Exit fullscreen mode

I defined two reactive variables via the $state() function.
Then, I implemented two functions, draw() and reset(), that act directly on the new variables dice and rolls.
So here I have 2 states and 1 derived function.
The two states are the random number generated and the rolls array to keep track of all the generated numbers.
The size of the rolls array indicates how many rolls we did.
Then, we have the average mathematical function, which is recalculated every time something changes in the array of rolls.
To make it reactive the average function we should set as $derived.
In the template part of the svelte component, you can use the variables and call the functions:

<section style="padding-top: 50px;">
  <button onclick={draw}> Let's draw </button>
  <button onclick={reset}> Let's restart </button>
</section>
<section>
  <h2 style="text-align: center">
    {dice == 0 ? "Let's start rolling" : 'Yes, another roll'}
  </h2>

  <section class="stats grid">
    <!-- Last number stat -->
    <div class="stats">
      <p class="label">Last number</p>
      <p class="count"><strong>{dice}</strong></p>
    </div>

    <!-- How many rolls stat -->
    <div class="stats">
      <p class="label">How many rolls</p>
      <p class="count"><strong>{rolls.length}</strong></p>
    </div>

    <!-- Average stat -->
    <div class="stats">
      <p class="label">Average</p>
      <p class="count"><strong>{average}</strong></p>
    </div>
  </section>

  {#each rolls as t, index}
    <p style="text-align: center">
      Rolling number {index + 1}, the dice says {t}
    </p>
  {/each}
</section>
Enter fullscreen mode Exit fullscreen mode

The first button calls the draw() function on the click event.
The second button calls the reset() function on the click event.
In the template, I'm using the 2 "state" variables, dice and rolls in the typical Svelte way (with #each directive for looping the rolls array).

Managing state in Svelte 5 via $state declaration

In Svelte 5, the $state() function simplifies managing state. To make a variable reactive, you simply declare it using the $state() function. This function enables the variable to automatically respond to changes, updating the UI without any extra setup.

In the example, I defined two "reactive" variables, the dice number and the rolls array.

let dice: number = $state(0);
let rolls: number[] = $state([]);
Enter fullscreen mode Exit fullscreen mode

Using the $derived function for reactive calculations in Svelte 5

In Svelte 5, the $derived function is perfect for creating reactive values that depend on other reactive state variables. For instance, if you want to calculate the average of values in the rolls array, you can define average as a $derived variable. This way, average will automatically re-calculate every time the roll changes, ensuring it stays in sync with the latest data.
To enhance execution performance, the derived function only recalculates when the underlying state (in this case, rolls) changes, rather than every time average is accessed. This optimization ensures efficient updates without unnecessary recalculations, improving responsiveness in Svelte 5 applications.

let average: number = $derived(rolls.reduce((t, n) => t + n, 0) / rolls.length);
Enter fullscreen mode Exit fullscreen mode

Using the new component

In the src/routes/+page.svelte file, I can use the new Svelte component:

<script>
    import Roller from "$lib/components/roller.svelte";
</script>

<main class="container">
    <Roller />
</main>
Enter fullscreen mode Exit fullscreen mode

Providing the style

For this quick example, I used the PicoCSS library, so in the src/app.html, you need to include it in your head section:

<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.indigo.min.css"
/>
Enter fullscreen mode Exit fullscreen mode

The Svelte5 component using the reactivity

Are you playing with the new Svelte 5?

I wrote this small article riding the excitement for the new announcement by Rich Harris on November 11th 2023 about Svelte 5 beta and then I've updated it with the official release of Svelte 5 (on October 2024): https://svelte.dev/blog/svelte-5-is-alive

Please share your thoughts in the comments section below if you have any feedback. I appreciate your input and value the community's insights. I am committed to keeping this article up-to-date with the latest developments in Svelte 5, so your contributions will be significant in ensuring it's accurate and relevant. Thank you for being part of this journey, and I look forward to exploring the exciting advancements that Svelte 5 has to offer together. Stay tuned for future updates!

Top comments (6)

Collapse
 
mfp22 profile image
Mike Pearson

dice could be downstream from rolls

This is how I'd do it in the next version of StateAdapt

const { draw, reset, $state: rolls } = adapt([0], {
  draw: state => [...state, (math random stuff)],
})
const dice = $derived(rolls[rolls.length - 1]);
Enter fullscreen mode Exit fullscreen mode

Just an idea. Probably on dangerous ground with the $state keyword. But it works

Collapse
 
robertobutti profile image
Roberto B.

Thank you for the feedback.
Managing arrays as a state is something that I'm exploring more in order to identify the "best way" to manage them.
For example, i want to replace adding item into an array with :

rolls = [...rolls, dice]
Enter fullscreen mode Exit fullscreen mode

I will monitor the side effects.
I want to explore more "Fine grained reactivity" https://www.youtube.com/watch?v=gGwnF-lxS_Q&t=313s

Collapse
 
robertobutti profile image
Roberto B.

With the new features of Svelte5 and the new reactivity mechanism, it is no longer necessary to reassign the array. An array is "reactive" if it is initialized with $state, and you can use the push method to append elements. (see the draw() function)

Collapse
 
mfp22 profile image
Mike Pearson

For my own future reference svelte-5-preview.vercel.app/#H4sIA...

Collapse
 
juanfrank77 profile image
Juan F Gonzalez

That's good stuff. Congrats. 👏

Collapse
 
robertobutti profile image
Roberto B.

I created a Svelte snippet for this example:
svelte.dev/playground/cdfabafb6c43...