As 2021 nears the halfway mark, the golden age of JavaScript continues. One of the most exciting characters in the current chapter is the Svelte framework. This article gives you the basics for creating a Svelte project and using some simple UI elements.
In a distinctive departure from the current groupthink represented by React, Angular, and Vue, Svelte works on the server side to compile your application into optimized JavaScript. That means that Svelte requires a build pipeline setup.
Although setting up a build pipeline might seem like extra work, the truth is that all real development in React, Angular, or Vue requires a build pipeline in some form anyway (like create-react-app or Webpack configuration). Plus setting up the Svelte environment quickly gets you things like hot-deploy dev mode.
Svelte setup
Let’s jump right in and set up a simple build environment. You are going to use npx and degit for the purposes of creating a starter template. Use the steps in Listing 1.
Listing 1. Initial template
npx degit sveltejs/template infoworld-svelte
cd infoworld-svelte
npm install
npm run dev
At this point the starter app will be running at localhost:5000; check it out in your browser. Open the /infoworld-svelte folder in your code editor or IDE. There are two source files of interest in the /src directory: App.svelte and main.js. These two work together to define what you see in the browser.
Note: All of the code is avaiable in this repo.
If you use Visual Studio Code, there are a number of useful (free) Svelte extensions that provide syntax highlighting and autocomplete.
To find them, go to the extensions tool on the left and enter “ext:svelte” into the search bar.
main.js is the main entry point for the app. It imports App.svelte
in the first line as seen in Listing 2.
Listing 2. main.js
import App from './App.svelte';
const app = new App({
target: document.body,
props: {
name: 'world',
}
});
export default app;
Listing 2 shows something interesting about how Svelte works: The export from App.svelte
has been transformed into an object, which is instantiated with the new App({...})
call.
The App
object is configured with a couple of parameters. These are used to supply the values for the Svelte object’s params. The target
param is a built-in property that Svelte uses to tell where the root of the app is (similar to the second argument of ReactDOM.render
).
Now look at App.svelte
. This has the meat of the component syntax in Svelte, which combines the three elements of JavaScript, markup, and CSS with script
, main
, and style
tags, respectively. These are combined together, along with the parameters provided by the instantiation in main.js, into a component. Note that the main
tag could be any valid HTML tag.
Notice that Svelte uses variable tokens in the same syntax as the other frameworks: <h1>Hello {name}!</h1>
. Notice also that this variable, whose value is supplied by the params in main.js, is exported in the script section: export let name;
. This could also be done directly in the script. To see what I mean, change this line to let name = "InfoWorld";
, eliminating the export entirely. The point being, there is nothing magical or required about parameterizing the App
object via main.js. It is just a supported feature for organizing things.
Since you are running in dev mode, the change will be reflected immediately. The browser will now show the new greeting, “Hello InfoWorld!”
The are many features necessary to building sophisticated UIs. Among the most essential are iterators and object handling. Let’s have a look by adding the code seen in Listing 3.
Listing 3. Iterating over an array of objects
<script>
let quotes = [
{author:"Emerson", quote:"To be great is to be misunderstood."},
{author:"James", quote:"The art of being wise is the art of knowing what to overlook."},
{author:"Thoreau", quote:"That government is best which governs least."}
];
</script>
<main>
<ul>
{#each quotes as { quote, author }, i}
<li>{i} - {quote}</li>
{/each}
</ul>
</main>
The basic syntax is the {#each}
tag. This is used to reference the variable quotes
. The elements of this array variable are then exposed (via destructuring) to the internals of the tag, along with an iterator counter i
. These exposed variables are then referenced with the same token syntax as any other variable. If you are familiar with another framework, I think you’ll agree the syntax is very concise here.
Event handling in Svelte
Adding handlers like onClick
is similarly easy. You can add one to the list items as seen in Listing 4.
Listing 4. Adding an onClick handler
<script>
...
function click(){ alert("ok"); }
...
</script>
<main>
...
<li on:click="{click}">{i} - {quote}</li>
...
</main>
The event handling syntax is fairly self-explanatory. You can also pass in params to the handler by wrapping the handler function, like so:
<li on:click="{() => click(author)}">{i} - {quote}</li>
This can be used by the handler function:
function click(author){ alert("hello from " + author); }
Svelte components and inputs
Now get a taste for the component system, along with two-way binding of input elements. You are adding a new component that will create quotes to add to the list. First, create a new file called /src/AddQuote.svelte and paste in the contents of Listing 5.
Listing 5. The AddQuote component (event dispatch and input binding)
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher(); // create dispatcher
let author = "";
let quote = "";
function onAdd(author, quote){
dispatch('quote', { // use dispatcher
author: author, quote: quote
});
}
</script>
<main>
<div class="add-quote">
<h2>New Quote</h2>
<div>Author: <input bind:value={author} placeholder="Author"></div>
<div>Quote: <input bind:value={quote} placeholder="Quote"></div>
<button on:click={()=>{onAdd(author, quote)}}>Add It!</button>
</div>
</main>
Component events
Several new concepts are introduced here. First is component events. These are events that components can raise and that are handled by other components just like DOM events. The basic process is to import the createEventDispatcher
from Svelte, then use it to create a dispatcher function. This dispatcher function is called and passed the name of the event ('quote'
) and the content of the event (in this case, the new quote information).
This event is then handled by our App
component, as we’ll see in a moment.
Input bindings
Binding the HTML inputs, aka two-way bindings, is also simple. You can see this in the main
element of Listing 5. Notice the bind:value
attributes on the input elements. These reference the variables to which the input will be bound—in this case, the author and quote variables.
You then use a button element with an onClick
handler to raise the dispatch event in the onAdd
function.
Catching custom events in Svelte
Back in the App.svelte file, you can use the AddQuote
component as seen in Listing 6.
Listing 6. Using the AddQuote component
<script>
...
function onAddQuote(event){
quotes = [...quotes, {author:event.detail.author, quote:event.detail.quote}];
}
</script>
...
<main>
...
<AddQuote on:quote={onAddQuote}></AddQuote>
...
</main>
Listing 6 shows how, in the markup, you use on:quote
to listen for the custom quote event and send it to the handler function, onAddQuote
, which is defined in the script section. This function is handed the event, which contains the event object we sent in AddQuote
in the event.detail
member.
From there it’s a simple matter of updating the data in the quotes
array to reflect the new item. Note though that you must update the array with an assignment, or Svelte won’t notice the change. In other words, just using Array.push
won’t trigger the update. (This is similar to other reactive frameworks.)
API fetching in Svelte
As a quick extra bonus, let’s see how quickly we can add a remote API fetch to this app. Listing 7 shows how to add an API fetch to App.svelte.
Listing 7. Using a REST API (App.svelte)
<script>
...
async function addRandom(){
const res = await fetch("https://api.quotable.io/random");
const json = await res.json();
quotes = [...quotes, {author:json.author, quote:json.content}];
}
</script>
...
<main>
...
<button on:click={addRandom}>Add Random Quote</button>
...
</main>
Listing 7 adds a button that calls the async addRandom
function. This function simply calls the remote quote API and then updates the quotes array with the new quote. Simple!
This has been a whirlwind tour of some key features of Svelte. There are many more capabilities in the framework, and it is up to the task of building enterprise interfaces right now.
Svelte is also making fast gains in the marketplace. It is fourth in usage after the big three (React, Angular, and Vue) but first in developer satisfaction and first in interest.