🎄 Get 50% off from our JavaScript course for the holidays! 🎄
Looking into Svelte 3

Looking into Svelte 3

Quickstart by creating a retro board in Svelte from scratch

Ferenc Almasi • 🔄 2021 November 11 • 📖 12 min read

If you’ve been a frontend developer you know that new releases of new frameworks are popping up every now and then. It seems like this trend hasn’t been slowing down.

Although Svelte has been around for a while now, version 3 has been just released a couple of months ago. It describes itself as a

radical new approach to building user interfaces

But why is it radical and how does it differ from other big frameworks like React, Angular, or Vue?

First of all, we need to point out that Svelte is a compiler, meaning it will generate your code at build time and only include JavaScript from the framework you actually use. This means that your bundle size will be smaller at the end which results in a more lightweight, faster app.

This also means that there’s not going to be a boilerplate code for your project. If you happen to write a hello world app, your bundle is not going to be 2MB, because if you don’t use anything from the framework, nothing from it will be included in the final build.

Reducing the amount of code you write is also an important aspect for Svelte. The following comparison is taken from the official site, comparing the same component in React and Svelte:

Svelte vs React Component comparison
React component on the left, Svelte component on the right

It also tries to bring reactivity at its core, there’s no need for external state management libraries.

To try and demonstrate its advantages while also covering core functionalities, we will create a retro board from scratch. Here is the initial design I came up with for the tutorial:

retro board created in Svelte

A classic three-column layout where you can post notes about what went well, what to improve on, and some action items to follow up. Users will be able to create, delete, edit, and clap each post-it.

I will provide a GitHub link for the project at the end of the article so you can avoid messing around with CSS first and jump straight into coding. So without wasting more time, let’s jump into setting up Svelte.

Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
JavaScript Course

Setting Up Svelte

The easiest and simplest way to start with Svelte is to head over to svelte.dev and either run this command if you have degit installed:

npx degit sveltejs/template svelte-board

or download and extract the zip file from the provided link. Either way, you will get the same template.

Downloading Svelte from svelte.dev

Install dependencies with npm i and run the server with npm run dev and you’re all set. If you look at the initial project structure, you will notice that Svelte uses rollup as a bundler. We are also presented with a public and a src folder. Everything that will be a publicly available asset, like fonts or images are supposed to go inside the public folder. Anything else related to your app should be in the src folder.

The project folder structure after installation

In the src folder, you’ll find an App.svelte file. You can delete the contents as we won’t use anything from it.

Now whenever I’m dealing with a new project, my first step is to get sass up and running to help me with CSS. As this article is supposed to be about Svelte, I won’t go into detail on how I replicated the design, instead I’m only going to guide you through how you can add support for sass.


Adding SCSS Support

For adding support, we’re going to need to npm i rollup-plugin-scss. After it’s done, open up your rollup.config.js file and add the following line to the end of the imports:

import scss from 'rollup-plugin-scss';
rollup.config.js
Copied to clipboard!

and call it with scss() at the end of the plugins array.

Adding scss support in Rollup config

All you have to do now is create an .scss file in your src folder and import it into main.js.


Creating Svelte Components

The next step is to create the main component. Svelte components have three main parts.

<script>
    // Scripts goes here
</script>

<style>
    // Scoped styles goes here
</style>

<!-- Everything else goes here -->
App.svelte
Copied to clipboard!

They have a script tag where the functionality of the component goes. They have a style tag where the styles live for the related component. It is scoped to the component by default so there’s no style collision. And of course, you have the markup itself.

If you’re not a fan of keeping scripts, styles, and templates together in one file, you can use import statements to import your scripts and CSS. For now, we can keep everything in one place.

To start out, add an empty script tag and the following to your App.svelte file:

<script>

</script>

<main class="app">
    <img src="assets/images/svelte-board.png" alt="logo" class="logo">

    <section class="grid">
        <div class="actions">
            <button>Went well <img src="assets/images/add.png" alt="add"></button>
            <button>To improve <img src="assets/images/add.png" alt="add"></button>
            <button>Action items <img src="assets/images/add.png" alt="add"></button>
        </div>

        <div class="columns">
            <div class="column column-1">
                <div class="item">
                    <span class="content">The content of the post-it</span>
                
                    <button class="remove">x</button>
                    <span class="claps">👏x0</span>
                </div>
            </div>


            <div class="column column-2">
                ...
            </div>

            <div class="column column-3">
                ...
            </div>
        </div>
    </section>
</main>
App.svelte
Copied to clipboard!

We will have three columns. Every column will have an item that will contain relevant information about the note; it’s content, the number of claps on it, and a remove button.

This is all static content, so let’s make it dynamic. We’re going to need to store the list of items we already have on the board, so let’s create a multidimensional array inside the script tag:

<script>
    let columns = [
        [{ content: 'Everything went well 👌' }],
        [],
        []
    ];
</script>
App.svelte
Copied to clipboard!

Each array will hold information about one column. Inside each array, we will have a list of objects with a content property. To display them in the template, we can use template expression and text literals.

Template expressions

Let’s display the contents of columns from the script tag by using the #each expression:

<div class="columns">
    <div class="column column-1">
        {#each columns[0] as item}
            <div class="item">
                <span class="content">{item.content}</span>
            
                <button class="remove">x</button>
                <span class="claps">👏x0</span>
            </div>
        {/each}
    </div>


    <div class="column column-2">
        {#each columns[1] as item}
            ...
        {/each}
    </div>

    <div class="column column-3">
        {#each columns[2] as item}
            ...
        {/each}
    </div>
</div>
App.svelte
Copied to clipboard!

Logic blocks and dynamic content is denoted by curly braces in Svelte. Apart from #each, you can also use #if block, and my favorite, #await for dealing with promises:

{#await promise}
      <p>loading...</p>
  {:then response}
      <p>{response.text}</p>
  {:catch error}
      <p>{error.message}</p>
{/await}
Promise.svelte
Copied to clipboard!

Back to the board, we will have the same content inside each column, meaning it’s a perfect opportunity to outsource them into a separate template that we can call inside each loop.

Using nested components

Create a new file in your src folder called Column.svelte and copy-paste the content of the post-it note into it.

<script>
    export let content;
</script>

<div class="item">
    <span class="content">{content}</span>

    <button class="remove">x</button>
    <span class="claps">👏x0</span>
</div>
Column.svelte
Copied to clipboard!

We’re going to need to pass the content of the post-it to the Column component and in order to do so, we have to export it here. We can now simplify our columns by importing the new component into the App component and use it inside the #each blocks.

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

<div class="columns">
    <div class="column column-1">
        {#each columns[0] as item}
            <column content="{item.content}">
        {/each}
    </column></div>

    <div class="column column-2">
        {#each columns[1] as item}
            <column content="{item.content}">
        {/each}
    </column></div>

    <div class="column column-3">
        {#each columns[2] as item}
            <column content="{item.content}">
        {/each}
    </column></div>
</div>
App.svelte
Copied to clipboard!

To pass the content of the items as a prop into the Column component, we can follow the same pattern React uses.

We have a pretty clean template now, so let’s start adding some functionality.


Event Handlers In Svelte

We want to have four different interactions in our app:

Let’s start with the adding and removing functionality.

To add new items, we want to push a new object into the columns variable. We want this to happen whenever any of the button below is clicked:

The button where we want to trigger the event

Let’s first create the function for it. Add the following to your script tag:

<script>
    const addItem = (column) => {
        columns[column] = columns[column].concat({
            content: "You can start editing by clicking here... 🙌"
        });
    }
</script>
App.svelte
Copied to clipboard!

Whenever an action button is clicked we call this function with an index, either 0, 1, or 2, depending on which column we want to add items to. All we do is here reassign the columns variable to an extended version of columns.

Why we are not using Array.push here, as we would elsewhere? This is because array mutating calls won’t trigger a re-render in Svelte. Instead, you need to reassign the variable. This is because Svelte reactions are based on assignments.

To add the function calls to the template, we can use on:click handlers:

<div class="actions">
    <button on:click={() => addItem(0)}>Went well <img src="assets/images/add.png" alt="add" /></button>
    <button on:click={() => addItem(1)}>To improve <img src="assets/images/add.png" alt="add" /></button>
    <button on:click={() => addItem(2)}>Action items <img src="assets/images/add.png" alt="add" /></button>
</div>
App.svelte
Copied to clipboard!

To pass params into the function, we can create an arrow function where we call addItem with the index of the column.

To remove them, we can add another on:click to the remove button inside the Column component and a single line to the script tag, which will remove the parent element from the DOM:

<script>
    const remove = (e) => e.target.parentElement.remove();
    export let content;
</script>

<div class="item">
    <span class="content" contenteditable="">{content}</span>

    <button class="remove" on:click="{remove}">x</button>
    <span class="claps">👏x0</span>
</div>
Column.svelte
Copied to clipboard!

I also added the contenteditable attribute to the content so users can edit it. All that’s left to do is implementing the clapping functionality.

For that, we can simply add a claps variable to the component and display its value. Every time we click on the element, we increase its value by 1:

<script>
    let claps = 0;
    
    const clap = (e) => claps++;
</script>

<div class="item">
    <span class="content" contenteditable="">{content}</span>

    <button class="remove" on:click="{remove}">x</button>
    <span class="claps" on:click="{clap}">👏x{claps}</span>
</div>
Column.svelte
Copied to clipboard!

Adding some animations

Let’s wrap things up by adding a cool slide-in animation. Svelte provides some nice API for simple fading, sliding, scaling, and blurring animations. The in: and out: events are used for animating an element in and out.

Import fly from svelte/transition and add it to the item:

<script>
    import { fly, scale } from 'svelte/transition';
</script>

<div class="item" in:fly="{{ y: 200, duration: 300 }}">
    ...
</div>
Column.svelte
Copied to clipboard!

This will animate each item in starting from -200px from its end position under 0.3 seconds:

Animations in Svelte

Summary

As promised, you can clone and tweak around with the project from GitHub.

Svelte is really fun to play with, there’s a ton of potential. It’s easy to get started, the learning curve is not steep. If you happen to stuck, the documentation is extensive and you have a number of examples ready at your disposal.

You can also play around with it online and download your code as soon as you start to outgrow it.

If you would like to learn more about using Svelte, check out how you can use it to create desktop apps:

How to Make Your Very First Desktop App With Electron and Svelte

If you haven’t started yet, go ahead and give Svelte a try! Otherwise, leave your thoughts on the framework. Thank you for sticking around and happy coding!

Learn Svelte in 30 days
Do you want to learn Svelte from the beginning with infographics? Check out the Svelte webtips
Share on
  • twitter
  • facebook
JavaScript Course Dashboard

Tired of looking for tutorials?

You are not alone. Webtips has more than 400 tutorials which would take roughly 75 hours to read.

Check out our interactive course to master JavaScript in 5 hours.

Learn More

Recommended

Ezoicreport this ad
🎉 Thank you for subscribing to our newsletter. x