Svelte in Five Minutes
A quick introduction to Svelte.
Introduction
This is a quick guide for newcomers to Svelte who already have a background on a web framework (preferably but not necessarily Vue.js). The reader is therefore expected to have some familiarity with HTML, CSS, and JavaScript.
Five Minutes
Minute 1: What is Svelte and Why Bother?
Svelte, on the surface, appears to be a framework like Angular, React, or Vue.js. While it shares the goal of simplifying the development of complex, interactive web applications, Svelte is not a framework runtime that runs in the web browser in the traditional sense.
Svelte, instead, is a compiler that generates standard HTML, CSS, and JavaScript (with no runtime frameworks). Svelte is:
- Lightweight: No framework runtime library overhead
- Fast: No virtual DOM since the DOM is manipulated directly by pure JavaScript statements
- Easy: Gentle learning curve given its minimalistic nature
For example, a component like Hello.svelete
is translated to something like this:
and is used like this
which results in this:
Hello World
Minute 2: What is the Anatomy of a Svelte Project?
Let’s consider a To Do application that doesn’t deviate much from the standard template produced using npx degit sveltejs/template my-svelte-project
as per the official Getting Started Guide:
My To Do List
.
├── README.md Instructions on how to build and run the project
├── node_modules Imported modules
├── package.json Dependencies
├── public Public static assets
│ ├── build *.js and *.css Svelte-Generated CSS and JavaScript
│ │ ├── bundle.css
│ │ ├── bundle.css.map
│ │ ├── bundle.js
│ │ └── bundle.js.map
│ ├── favicon.png
│ ├── global.css
│ └── index.html
├── rollup.config.js Bundler config
└── src *.svelte User-defined Svelte Components
├── App.svelte The top topmost component
├── TodoList.svelte List of items (with Delete function)
├── TodoAdd.svelte Text box to Add New Item
└── main.js Top component declaration (Svelte app entry point)
Regular .svelte
components have three compartments: a <script>
JavaScript compartment for code</script>
, the componet’s HTML, and a <style>
compartment for CSS </style>
, for example:
<!-- App.svelte -->
<script>
import TodoList from './TodoList.svelte';
import TodoAdd from './TodoAdd.svelte';
let myList = ["clean kitchen", "do 10,000 steps"];
function addItem(description) {
myList = [...myList,description]
}
</script>
<main>
<div class="title">My To Do List</div>
<TodoList bind:todoItems={myList}/>
<TodoAdd on:new-item-event={({detail}) => addItem(detail)}/>
</main>
<style>
.title {
font-weight: bold;
font-size: 14pt;
}
</style>
Minute 3: How to Set Components’ Properties
A component’s property is specified using the export let
property declaration as follows:
<!-- TodoList.svelte -->
<script>
export let todoItems;
</script>
<div>
I have <b>{todoItems.length} items</b> left to complete!
</div>
When the component is instantiated, the variable may be passed unidirectionally as follows:
<!-- App.svelte -->
<script>
let myList = ["clean kitchen", "do 10,000 steps"];
</script>
<TodoList todoItems={myList}/>
If we want myList
to be indirectly updated (via todoItems
) when changed from within TodoList.svelte
, then we need to create a bidirectional binding as follows:
Important Note: Setting the internal structure of myList
using the likes of push()
will not cause Svelte to render the changes. The trigger for Svelte to render the change of a variable is an assignment statement. For example:
<!-- App.svelte -->
<script>
let myList = ["clean kitchen", "do 10,000 steps"];
function addItem(item) {
// myList.push(item) Don't do this
myList = [...myList,item] // Do this instead!
}
</script>
Minute 4: How To Make Components Talk To Their Parents
Although properties using the bind:variable
can be used for components to exchange data back and forth with their parents, this is not an ideal mechanism to notify of events because that would require parent components to keep watching for changes in the variables shared with their children.
Let’s suppose that the TodoAdd.svelte
component wants to notify App.svelte
that the a new To Do item has been created:
<!-- TodoAdd.svelte -->
<script>
let item = ""
function add() {
// How do I tell my parent?
}
</script>
<input type="text" id="description" bind:value={item}/>
<button type="button">Add</button>
The first step is to assign an on:click
event handler to the Add button:
The second step is to send the item description “out” using the dispatch
function:
<!-- TodoAdd.svelte -->
<script>
import { createEventDispatcher } from 'svelte'
const dispatch = createEventDispatcher();
let item = ""
function add() {
dispatch("new-item-event",item);
item = ""
}
</script>
The third step is to catch the event on the parent and so something with it, such as appending the item to the list:
<!-- App.svelete -->
<script>
let myList = ["clean kitchen", "do 10,000 steps"];
function addItem(event) {
let item = event.detail // Our item is inside here!
myList = [...myList,item]
}
</script>
<TodoAdd on:new-item-event={addItem}/>
If we want to avoid the boiler plate of extracting the event.detail
variable every time and have a clean function such as addItem(item)
instead, we can use the following trick:
Minute 5: How to Declare Logical Conditions
Logical conditions, like JavaScript expressions, are enclosed in {
single curly braces }
but use special keywords. This is an example of an If
condition:
<!-- App.svelte -->
{#if myList.length === 0}
<div>All done. Great!</div>
{:else}
<TodoList bind:todoItems={myList}/>
{/if}
And this is example of traversing a list:
<!-- TodoList.svelte -->
<ul>
{#each todoItems as items, i}
<li> item [ <span on:click={delete(i)}>delete</span> ]</li>
{/each}
</ul>
For convenience, the delete()
function is provided below: