Svelte Tutorial: A Thorough Introduction to SvelteJs

In this SvelteJS guide, we will take a thorough look at what is SvelteJS? And how it uses a unique approach to build web applications. Let’s dive in and explore.

1. What is Svelte?

Svelte is an open-source component-based JavaScript framework that allows us to create user interfaces by writing composable components.

The Svelte app is compiled beforehand and it only updates the necessary parts of the DOM. As a result, the execution time is extremely fast. Also, unlike other frameworks such as React, Vue, etc. Svelte does not use Virtual DOM.

2. Get started with Svelte

To start with Svelte, first of all, you should install Node.js v6.0 or higher, if you don’t have it already.

There are several ways to install and use Svelte on your machine. In this article, we’re going to use degit.

npx degit sveltejs/template first_app 

(If you’re having issues with degit you can download the zip file directly from HERE)

cd first_app
npm install
npm run dev

Once you have completed all the steps then you can go ahead and check localhost:5000

3. Svelte Components

What is a web component? Web components are the building blocks of any web application. Each individual component represents a small piece of an application i.e a login page.

Svelte is based on modern web components that contain HTML, CSS, and JavaScript. These components are written into .svelte files.

Here is a quick example of a Svelte file:

<!--- Message.svelte --->

<script>
  let message = “Hello World”
</script>

<style>
  h1 { color: red;}
</style>

<h1>{message}</h1>

NOTE: JavaScript and CSS must be written inside script and style tag respectively.

3.1 Nested Components

It will be impractical to use a single component in an application. In Svelte, a component can be imported in other components.

Example: we can import Message.svelte in App.svelte:

<!--- App.svelte --->

<script>
  import Message from ’./Message.svelte’;
</script>

<Message />

3.2 Export variables and functions

To export a component, we don’t have to do write any code because, in Svelte, all the components are exported by default.

On the other hand, if you want to export a variable, it should be written inside the script tag. Also, we can assign a default value to the variable.

<!--- Message.svelte --->

<script>
  export let message = "Hello World"
</script>

<style>
  h1 { color: red;}
</style>

<h1>{message}</h1>

Example: how to access exported variable:

<!--- App.svelte --->
<script>
  import Message from ’./Message.svelte’;
</script>

<Message
  message = "I'm learning svelte"
/>

4. Svelte Reactivity

Whenever the state of a component changes, Svelte automatically updates the DOM.

Often, in an app, we need to compute one variable from other variables. for example, the addition of two numbers which is derived from two different input values;

Example: updating a variable by clicking a button:

<script>
  let count = 0;
  function updateCount() {
    count++;
  }
</script>

<button on:click={updateCount}>Click Count</button>

<p>{count}</p>

4.1 Reactive Variable

In Svelte, we have a special prefix $: that converts a general variable into a reactive variable.

<script>
  let x = 5;
  let y = 3;
  
  $: total = x+y;
</script>

<button on:click={()=> x += 1}>Change x</button>
<button on:click={()=> y += 1}>Change y</button>

<p>{total}</p>

In this example, we have created a reactive variable called total so that whenever x or y changes, it will automatically update its value.

In addition to variables, we can also make console logs reactive.

<script>
  let count = 0;
  function updateCount() {
    count++;
  }

  $: console.log(count);
</script>

<button on:click={updateCount}>Click Count</button>

5. State Management in Svelte

We have already seen that handling the state of a single component is extremely easy in Svelte.

Svelte provides multiple ways to pass the state across different components. Let’s break them down:

5.1 Props

In Svelte, props are used to pass a state downward through the component tree. This is a common strategy among modern UI frameworks.

We can pass either a variable or an expression through a prop.

<Component prop1={varA} pro2={varA + varB} />

Whenever a prop changes, Svelte will automatically re-rendered the child component.

5.2 Events

Events are the opposite of props. They allow a child component to pass a state change to a parent component.

To use events, we need to create a dispatcher.

<!--- parent component -->
<script>
  import Child from ’./Child.svelte’;

  // Event Handler
  function handleData(data) {
    // write something;
  }
</script>

<Child on:callBack={handleData} />
<!--- child component --->
<script>
  import {createEventDispatcher} from 'svelte';

  // create an event dispatcher;
  const dispatch = createEventDispatcher();

  // random on click function
  function handleClick() {
    dispatch('callBack', {data: 'some data'});     // fire an event called callBack
  }
</script>

5.3 Context

There are few cases where props are not practical to use. For example, if in a large application, two components are so distant in the component tree that we have to move a state up to the top-level component.

To solve this issue, Svelte provides context API. It is really useful if we don’t want to pass props across multiple components but they can communicate with descendants.

There are two functions provided by context API:

5.3.1 setContext

We can set an object in the context.

<!-- First.svelte -->

<script>
  import { setContext } from 'svelte';

  setContext('number', 111);
</script>

5.3.2 getContext

getContext() is used to retrieve the context that belongs to the closest parent component with the specified key.

Example: get context from the First.svelte in Second.svelte

<!-- Second.svelte -->

<script>
  import { getContext } from 'svelte';

  let my_number = getContext('number');
</script>

5.4 Stores

Imagine, in a large application, if a great-grandchild needs a top-level prop, passing that prop through every single component can be a tedious process.

To solve this issue, Svelte uses stores that can centralize a state, which means any child component (even in different component trees) can import a variable without any hassle.

There are three types of stores:

5.4.1 Writable Stores

First of all, to create a store, we need to import writable from svelte/store.

After that, we can create a store variable using writable() function, while passing a default value.

import { writable } from 'svelte/store';

const message = writable('hello world');

Note: writable can be declared in different files including JavaScript files. To access those variables inside our components, simply add the prefix export.

Whenever we create a new writable, it gets created as an object with two methods:

5.4.1.1 Set

To set a new value to our existing writable, use the set() function which takes one argument.

import { writable } from 'svelte/store';

const message = writable('hello world');

message.set('My name is var A');
5.4.1.2 Update

A writable can also be updated using the update() function. In update(), we run a callback function that passes the current value of the variable as its argument. That is the main difference between update() and set().

<script>
  import { writable } from 'svelte/store';

  const total_count = writable(0);

  // update total_count.
  function handleClick() {
    total_count.update(val => val + 1);
  }
</script>

<button on:click={handleClick}> click here </button>

Now, we know how to create a writable and set or update its value. Let’s talk about how to get the value of a writable:

To get the value of an existing writable, we can use the get() function exported by svelte/store.

import { writable, get } from 'svelte/store';

const message = writable('hello world');

get(message); // 'hello world'

In Svelte, we can also get the value of a store reactively by using prefix $.

import { writable } from 'svelte/store';

const message = writable('hello world');
console.log($message); // 'hello world'

message.set('something');
console.log($message); // 'something'

Another option, if you need to execute some logic then we can use subscribe() method:

message.subscribe(msg=> {
  console.log(msg);
});

5.4.2 Readable Stores

Readable stores are unique because once you set the initial state then they can’t be updated from outside. Also, there is no set() or update() method.

To update the default value of a readable, we can have a function after the default value.

Here is an example:

import { readable } from 'svelte/store'
const count = readable(0, set => {
  setTimeout(() => {
    set(1)
  }, 1000)
});

5.4.3 Derived Stores

Derived stores allow us to create a new store value from one or more existing stores.

To use derived stores, we have to import derived() function exported by svelte/store. Derived takes an existing store value as the first argument, and a function as second argument, which receives that store value as its first argument.

import { writable, derived } from 'svelte/store';

const message = writable('Hello World!');

const name = derived(message, $message=> {
  return `${$message} My name is John Cena`;
})

console.log($name) // Hello World! My name is John Cena

6. Svelte Slots

In Svelte, components can be composed together using slots. In simple words, we can contain other components in a component.

We can define a slot using the <slot /> or <slot></slot> syntax.

<!-- Book.svelte -->
<script>
  export let title;
</script>

<div>
	<slot />
</div>

We can also add a default value in a slot which is being used, if the slot is not filled:

<div>
  <slot>
    <p>Default value...</p>
  </slot>
</div>

Let’s use Book.svelte in a new component:

<!-- App.svelte -->
import First from "./First.svelte";

let book_data = [
  {
    title: "Harry Potter",
    desc: "Blah Blah"
  },
  {
    title: "Lord of the Rings",
    desc: "Blah Blah"
  }
];

{#each book_data as data}
  <Card title={data.title}>
    <hr />
    <p>{data.desc}</p>
  </Card>
{/each}

7. Svelte Bindings

In Svelte, we can create a two-way binding between data and the UI. It is a common technique among modern web frameworks.

7.1 bind:value

Let’s take a variable and bind it to a form using bind:value

<script>
  let message = ''
</script>

<input bind:value={message}>

whenever input field or message changes, it will update the other place.

Note: We can not define a variable using const. It has to be a let or var.

bind:value also works with the select form field to get the selected value.

<script>
  let selected;
</script>

<select bind:value={selected}>
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
</select>

console.log(selected)

7.2 bind:checked

bind:checked is used to bind a value to the checked state of an element:

<script>
  let is_checked;
</script>

<input type=checkbox bind:checked={is_checked}>

7.3 bind:group

In Svelte, bind:group is useful with checkboxes and radio buttons.

We can associate a JavaScript array with a list of checkboxes.

<script>
	let own_books = '1';
	let book_title = [];
</script>

<!-- grouped radio inputs are mutually exclusive -->
<input type="radio" bind:group={own_books} value="1">
<input type="radio" bind:group={own_books} value="2">
<input type="radio" bind:group={own_books} value="3">

<!-- grouped checkbox inputs populate an array -->
<input type="checkbox" bind:group={book_title} value="Harry Potter">
<input type="checkbox" bind:group={book_title} value="lord of the rings">
<input type="checkbox" bind:group={book_title} value="The Hunger Games">
<input type="checkbox" bind:group={book_title} value="The Witcher">

8. Svelte Lifecycle events

In Svelte, every component has a lifecycle that starts when it is created and ends when it is destroyed.

These events are useful if we want to schedule a function whenever Svelte fires an event. Also, we can use these events to add js libraries such as jQuery, Chartjs, etc.

Let’s talk about different types of events:

8.1 onMount

Svelte fires onMount event after a component is rendered.

The most common use of onMount is to fetch data from other sources.

<script>
  import { onMount } from 'svelte'

  onMount(async () => {
    //do something on mount
  })
</script

8.2 onDestroy

Svelte fires onDestroy event after a component is destroyed.

onDestroy is used to clean up data or stop any operation that we have started during the component initialization.

import { onMount, onDestroy } from 'svelte';

let element;
onMount(() => {
  element = fetch something..... 
});

onDestroy(() => {
  if (element) {
    element.destroy();
  }
});

Svelte component also acts similar to destroy, if the onMount event returns a function.

import { onMount, onDestroy } from 'svelte';

let element;
onMount(() => {
  element = fetch something.....;

  return () => {
    element.destroy();
  };
});

8.3 beforeUpdate

Svelte fires beforeUpdate event before the DOM is updated.

<script>
  import { beforeUpdate } from 'svelte';
	
  beforeUpdate(() => {
    console.log('the component is going to be updated');	
  });
</script>

8.4 afterUpdate

Svelte fires afterUpdate event after the DOM is updated

<script>
  import { afterUpdate} from 'svelte';

  afterUpdate(() => {
    console.log('the component has been updated');	
  });
</script>

9. Conditional Logic in Svelte Templates

Just like all the major templating languages, In Svelte, we can use two types of logic: conditional structure and loops. These logics are really useful to create our user interface in a specific way.

9.1 Conditional Structure:

Let’s start with if.

To use if block, we have to start with {#if} and in the end, we can close it using {/if}.

The first markup checks our conditions. Here is an example:

<script>
  let color = "white";
<script>

{#if color == "white"}
  Color is white
{/if}

We can also use else condition by using {:else}

<script>
  let color = "black";
<script>

{#if color == "white"}
  Color is white
{:else}
  Color is black
{/if}

Let’s add an else if condition:

<script>
  let color = "blue";
<script>

{#if color == "white"}
  Color is white
{:else if color == "blue"}
  Color is blue
{:else}
  Color is black
{/if}

9.2 Loops

In Svelte, we can create a loop using the {#each}{/each} syntax

<script>
  let names = ['Jack', 'John']
</script>

{#each names as name}
  <li>{name}</li>
{/each}

We can also get the index of the iteration. Index always starts from 0.

<script>
  let names = ['Jack', 'John']
</script>

{#each names as name, i}
  <li>{i}: {name}</li>
{/each}

In templates, We can pass a list of objects. Here is an example:

<script>
  let list_names = [
    {id: 1, name: 'Jack'}, 
    {id: 1, name: 'John'}
  ]
</script>

{#each list_names as names}
  <li>{names.id} {names.name}</li>
{/each}

10. Promises in Templates

Promises are really useful to work with asynchronous events in JavaScript.

In Svelte, we can structure our templates according to various states of a promise: resolved, unresolved, and rejected.

Let’s see how it works.

  • We can use {#await} block to wait for a promise to resolve.
  • Once the promise is resolved, then the result is passed to {:then} block.
  • To detect a promise rejection, we can use {:catch} block.
<script>
  let random_promise = new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve('hello world');
    }, 2000);
  });
</script>

{#await random_promise}
  waiting for promise to resolve...
{:then data}
  {data} // print resolved data
{:catch error}
  An error occurred.
{/await} 

11. What’s Next

I hope this introduction was helpful to you to understand what is Svelte, and what can you do with it.

If you want to learn more about Svelte then visit the official svelte website. 🙂

Frequently Asked Questions

What is Svelte used for?

Svelte is an open-source component-based JavaScript framework. Like its counterparts React and Vue, it is used to build entire web apps.

Is Svelte better than React?

All the modern web frameworks are achieving same goal of building web apps.

There is three key difference between Svelte and other frameworks like React, Vue, or Angular:

  1. The app execution time is extremely fast in Svelte because the app is compiled beforehand and it only updates the necessary parts of the DOM.
  2. Also, unlike other frameworks, Svelte does not use Virtual DOM.
  3. Bundle size is tiny compared to React that may be achieved because of the use of Rollup.

Is Svelte worth learning?

Absolutely, Svelte is an interesting web framework. Even though Svelte is a relatively new framework, it is being developed every single day.

Who created Svelte?

Svelte is written by Rich Harris.

Who uses Svelte?

There are many big names in the industry are using Svelte such as Rakuten, GoDaddy, 1Password, etc. You can find more information regarding the question at “Who’s using Svelte?” on the official website.