Notes on Svelte
I had a play around with Svelte the other day and wanted to make a few notes and comparisons to React, React being a point of reference for me and hopefully others.
I’ve found a lot of the examples here on
There’s also the Svelte docs with interactive tutorials which I’m going through.
As Svelte looks really similar to html styling is done pretty much the same way.
Want to add functionality add script
tags want to add style add
style
tags.
A simple Svelte component could look something like this:
1<!-- Simple component -->2<!-- Circle.svelte -->3<script>4 // use export so that text can be accepted as a prop5 export let text = 'hello world'6</script>7
8<div>{text}</div>9
10<style>11 div {12 height: 200px;13 width: 200px;14 margin: 20px;15 font-size: 2rem;16 background-color: #663399;17 color: #fff;18 border-radius: 9999px;19 display: flex;20 align-items: center;21 justify-content: center;22 }23</style>
Then that can be used by App.svelte
like this:
1<!-- App.svelte -->2<script>3 import Circle from './Circle.svelte'4</script>5
6<main>7 <Circle />8</main>
In the component I defined the prop with export let text
which is
defaulted to hello world
but I can pass in my own prop to the
Circle
component to replace it!
1<!-- App.svelte -->2<script>3 import Circle from './Circle.svelte'4</script>5
6<main>7 <Circle text="wheeeeee" />8</main>
Styling
Each components styles are scoped so if I want to import a goat image as a component:
1<!-- App.svelte -->2<script>3 import Goat from './Goat.svelte'4</script>5
6<main>7 <Goat />8</main>
The Goat
component is an image tag with some styles scoped to it:
1<!-- Goat.svelte -->2<img3 alt="adorable goat"4 src="https://images.unsplash.com/photo-1533318087102-b3ad366ed041"5/>6
7<style>8 img {9 height: 200px;10 }11</style>
The styles in the component are scoped so if there’s any styles that
need to be applied in the parent (App.svelte
) then then all that can
be affected is the wrapping element for it:
1<script>2 import Goat from './Goat.svelte'3</script>4
5<!-- This only affects the wrapping div -->6<main>7 <div class="goat-wrapper">8 <Goat />9 </div>10</main>11
12<style>13 .goat-wrapper {14 height: 400px;15 background-color: cornflowerblue;16 }17</style>
There is a global
directive that you can use this will target
anything in the class matching that element:
1<script>2 import Goat from './Goat.svelte'3</script>4
5<!-- This only affects the wrapping div -->6<main>7 <div class="goat-wrapper">8 <Goat />9 </div>10</main>11
12<style>13 .goat-wrapper {14 height: 400px;15 background-color: cornflowerblue;16 }17 .goat-wrapper :global(img) {18 height: 400px;19 }20</style>
Slots
You can nest other elements in a component with a slot
a slot is
much like the children
prop in React.
If I take the Circle
component and add a slot
to it:
1<div><slot /></div>2
3<style>4 div {5 overflow: hidden;6 height: 200px;7 width: 200px;8 margin: 20px;9 font-size: 2rem;10 background-color: #663399;11 color: #fff;12 border-radius: 9999px;13 display: flex;14 align-items: center;15 justify-content: center;16 }17</style>
Then I can nest other components in it:
1<script>2 import Circle from './Circle.svelte'3 import Goat from './Goat.svelte'4</script>5
6<main>7 <div class="goat-wrapper">8 <Goat />9 <Circle>10 <Goat />11 </Circle>12 </div>13</main>14
15<style>16 .goat-wrapper {17 height: 400px;18 background-color: cornflowerblue;19 }20 .goat-wrapper :global(img) {21 height: 400px;22 }23</style>
Event handlers
The on:click
is used pretty much the same as with React. Here I’m
cycling through some goat pics on click:
1<script>2 const goats = [3 `https://images.unsplash.com/photo-1533318087102-b3ad366ed041`,4 `https://images.unsplash.com/photo-1585082868368-58be13852617`,5 `https://images.unsplash.com/photo-1540392015439-4cc83fc3c1cf`,6 ]7 export let goatsIndex = 08 export function nextGoat() {9 if (goatsIndex + 1 === goats.length) goatsIndex = 010 goatsIndex += 111 }12</script>13
14<img alt="adorable goat" src="{goats[goatsIndex]}" />15<button on:click="{nextGoat}">Next Goat</button>16<!-- Alternatively to pass the event to the function -->17<!-- <button on:click={(e) => nextGoat(e)}>Next Goat</button> -->18<style>19 img {20 height: 200px;21 }22</style>
Conditional render (if blocks)
Conditional rendering in Svelte is a bit different to React whereas in React I’d break out into JavaScript in Svelte there’s a special notation used.
1<script>2 import Goat from './Goat.svelte'3 import Sloth from './Sloth.svelte'4
5 let animal = 'sloth'6</script>7
8<main>9 {#if animal === "sloth"}10 <Sloth />11 {:else if animal === "goat"}12 <Goat />13 {:else} No animal {/if}14</main>
HTML for loop
Looping over arrays is done with the #each
directive with similar
format to the #if
directive.
1<script>2 const cats = [{ name: `Boris` }, { name: `Leo` }, { name: `Darcy` }]3</script>4
5<main>6 {#each cats as cat}7 <div>{cat.name}</div>8 {/each}9</main>
Context
Context in Svelte is simpler than with React, in React to define some
context you’d need to create context provider which would then need to
live high up in the render tree (app.js
) along with the other
providers.
In Svelte you pull out the setContext
function from Svelte then give
that context a key and what you want to set that key to.
Check out the App.svelte
example here:
1<script>2 import { setContext } from 'svelte'3 import Goat from './Goat.svelte'4 import Sloth from './Sloth.svelte'5
6 setContext('sloth', incrementSloth)7
8 let slothCount = 09 function incrementSloth() {10 slothCount++11 }12</script>13
14<main>15 <Sloth {slothCount} />16 <Goat />17</main>
Then in Sloth.svelte
use getContext
to use the incrementSloth
function from App.svelte
:
1<script>2 import { getContext } from 'svelte'3
4 let incrementSloth = getContext('sloth')5 export let slothCount6</script>7
8<img9 alt="adorable sloth"10 src="https://images.unsplash.com/photo-1576612119302-7b7e8f824e5f"11/>12
13{slothCount}14<button on:click="{incrementSloth}">Bump Sloth</button>15
16<style>17 img {18 height: 200px;19 }20</style>
Reactivity
This is where a lot of people get their knickers in a twist with Svelte and to be honest I’m fine with it.
Svelte uses the JavaScript label statement for when you want to change a components state when it’s created from the state of another component.
Here’s the example take from the Svelte.dev titorial site:
1<script>2 let count = 03 $: doubled = count * 24
5 function handleClick() {6 count += 17 }8</script>9
10<button on:click="{handleClick}">11 Clicked {count} {count === 1 ? 'time' : 'times'}12</button>13
14<p>{count} doubled is {doubled}</p>
Use state hooks
Take a look at the following example from the React documentation for Introducing Hooks which is a simple counter component:
1import React, { useState } from 'react'2
3function Example() {4 // Declare a new state variable, which we'll call "count"5 const [count, setCount] = useState(0)6
7 return (8 <div>9 <p>You clicked {count} times</p>10 <button onClick={() => setCount(count + 1)}>Click me</button>11 </div>12 )13}
Now take a look at the same example in Svelte:
1<script>2 let count = 03</script>4
5<p>You clicked {count} times</p>6<button on:click={() => count++}>7 Click me8</button>
They both do the same thing and the Svelte one is a little shorter and a lot simpler to grok.
Resources
Check out Svelte Mastery for all these examples and more
Back to Top