Looking into Svelte 3

Looking into Svelte 3

Quickstart by creating a retro board in Svelte from scratch
Ferenc AlmasiLast updated 2021 November 11 • Read time 12 min read
Svelte 3 promises a radical new approach to building user interfaces. Since it is a compiler, it works fundamentally different from other big frameworks...
  • twitter
  • facebook

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.


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:

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

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.

Looking to improve your skills? Learn how to build reactive apps with Svelte + Tailwind.
Master Svelteinfo Remove ads

Creating Svelte Components

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

Copied to clipboard!
<script>
    // Scripts goes here
</script>

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

<!-- Everything else goes here -->
App.svelte

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:

Copied to clipboard!
<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

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:

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

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:

Copied to clipboard!
<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

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:

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

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.

Copied to clipboard!
<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

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.

Copied to clipboard!
<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

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:

  • Add new items
  • Remove items
  • Edit existing items
  • And clap them if we like the idea.

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:

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

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:

Copied to clipboard!
<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

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:

Copied to clipboard!
<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

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:

Copied to clipboard!
<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

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:

Copied to clipboard!
<script>
    import { fly, scale } from 'svelte/transition';
</script>

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

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
  • twitter
  • facebook
Did you find this page helpful?
📚 More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Access 100+ interactive lessons
  • check Unlimited access to hundreds of tutorials
  • check Prepare for technical interviews
Become a Pro

Courses

Recommended

This site uses cookies We use cookies to understand visitors and create a better experience for you. By clicking on "Accept", you accept its use. To find out more, please see our privacy policy.