Svelte is a tool for building web apps
It’s mostly JS but with some helpful extras
Unlike other frameworks it is compiled.
This means you run a program to generate your final app.
Svelte components can define markup, styles & behaviour.
All in one place!
E.g. if we had a file at src/Hello.svelte
<script>
console.log("hi from JS");
</script>
<h1>Hello</h1>
<style>
h1 {
font-size: 2rem;
}
</style>
We could render that component somewhere else:
<!-- src/App.svelte -->
<script>
import Hello from "./Hello.svelte";
</script>
<Hello />
<div>Other stuff</div>
The above CSS rule is scoped to just that component.
The final markup is something like:
<style>
.e7zmn {
font-size: 2rem;
}
/* ...other styles... */
</style>
<h1 class="e7zmn">Hello</h1>
<div>Other stuff</div>
React components re-render whenever you update state values.
For this to work you have to tell React what values are state, and when you plan to update them.
E.g. here’s a counter component:
function Counter() {
let [count, setCount] = useState(0);
return <button onClick={() => setCount(count + 1)}>Count: {count}</button>;
}
Here’s the same thing as a Svelte component:
<script>
let count = 0;
</script>
<button on:click="{() => count += 1}">Count: {count}</button>
Svelte tracks all top-level variables that can change.
It re-renders the component when you assign to them.
It’s common to need to run side effects after state updates.
E.g. in React:
function Counter() {
let [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
// ...
}
In Svelte:
<script>
let count = 0;
$: document.title = `Count: ${count}`;
</script>
<!-- ... -->
Svelte automatically re-runs lines starting with $:
.
But only when the state values used within change.
This is all kind of magic, but in a good way.
You don’t have to think about it, stuff is just always up-to-date.
Svelte can express complex interactions with very little code.
Here’s a component for adding 2 numbers in React:
import React, { useState } from "react";
export default () => {
const [a, setA] = useState(1);
const [b, setB] = useState(2);
return (
<>
<input type="number" value={a} onChange={(e) => setA(+e.target.value)} />
<input type="number" value={b} onChange={(e) => setB(+e.target.value)} />
<output>
{a} + {b} = {a + b}
</output>
</>
);
};
Here’s the same in Svelte:
<script>
let a = 1;
let b = 2;
</script>
<input type="number" bind:value="{a}" />
<input type="number" bind:value="{b}" />
<output>{a} + {b} = {a + b}</output>
Svelte generates normal DOM manipulation (like you’d write yourself).
Keeping data in sync with the DOM is a big frontend problem.
E.g. “user clicked +, count incremented, show new count on page”.
Frameworks like React chose the simple approach:
render everything, compare to last time, update what changed.
E.g. when we update this component:
function Count() {
let [count, setCount] = useState(0);
return (
<button onClick={() => setCount(count + 1)}>
<span>Count: {count}</span>
<p>Unrelated</p>
</button>
);
}
React does this comparison:
let prev = {
type: "button",
children: [
{ type: "span", children: ["Count: ", "0"],
{ type: "p", children: ["unrelated"] },
],
};
let next = {
type: "button",
children: [
{ type: "span", children: ["Count: ", "1"],
{ type: "p", children: ["unrelated"] },
],
};
let toUpdate = diffSomehow(prev, next); // only the "Count: 0"
However comparing large trees of objects like this can be expensive.
This is why React can be laggy when changing a lot of DOM nodes.
If you were handling the update manually:
if (countChanged) {
spanElement.textContent = `Count: ${count}`;
}
Since Svelte is compiled the code you write isn’t run by the browser.
Here’s the same counter:
<script>
let count = 0;
</script>
<button on:click="{() => count += 1}">
<span>Count: {count}</span>
<p>Unrelated</p>
</button>
will compile down to regular DOM manipulation.
Here’s a snippet:
let span = element("span");
let t0 = text("Count: ");
let t1 = text(/*count*/ "0");
span.append(t0, t1);
// ...
function update(dirty) {
if (dirty) t1.textContent = "1";
}
Svelte knows in advance what values might change.
It can create very granular update code.
Svelte has the opposite philosophy to React.
It has a ton of useful stuff built-in.
E.g. animation helpers, conditional classnames, grouped input state, easy scroll binding and more
The Svelte website has a playground where you can start building.
You can download this to continue working locally.
Svelte apps must be compiled.
Usually with a bundler like Rollup (same creator).
npx degit sveltejs/template your-project-name
SvelteKit is like Next.js for Svelte.
Still in beta but helps you build prod-ready multi-page apps.
The official tutorial is a fantastic interactive guide: