Svelte is a web framework for writing rich user interfaces. Here’s a quick guide on Svelte 3.0.
The easiest way to learn Svelte (in my opinion) is the examples documentation. It’s comprehensive and straight-to-the-point.
Svelte components store the markup, script and CSS styles in one .svelte
file.
<script> let name = "Rico";</script><div> hello {name}!</div><style> div { color: dodgerblue; }</style>
Using export let
will define a component property.
<script> import Nested from './Nested.svelte';</script><div> My message is: <Nested message="Hello there" /></div>
<script> export let message;</script><div> {message}</div><style> div { color: purple; }</style>
Styles are scoped per component, but :global(…)
will allow styling elements outside the component.
<p> Only this will be red.</p><style> p { color: red; } p :global(a) { color: blue; }</style>
Attributes are in HTML syntax, and can contain JavaScript expressions inside {…}
brackets.
<img src={src}><img src="{src}"><img src="https://{src}"><img {src}> <!-- shorthand --><img {...props}> <!-- spread -->
Updating variables declared with let
will trigger DOM updates.
<script> let count = 0; // state</script>
<button on:click={() => { count++ }}> I was clicked {count} times</button>
Prefixing statements with $:
will make it run with changes to the states it depends on.
<script> let count;
// reactive state derived from `count` $: doubled = count * 2;</script>6 collapsed lines
<button on:click={() => { count++ }}> Count: {count}</button>
<p>{count} * 2 = {doubled}</p>
$:
works with blocks too. Only values which directly appear within the $: block will become dependencies of the reactive statement.
<script> // runs when the `title` prop changes $: document.title = title;
// reactive block $: { console.log('title is', title); }</script>
#if
) {#if answer === 42} Yes{/if}
:else
) {#if answer === 42 && a !== b} Yes{:else if answer === 74 || b > c} Maybe{:else} No{/if}
#each
) {#each items as item} <li>{item.name} x {item.qty}</li>{/each}
<!-- With index: -->{#each items as item, index} <li>{i + 1}: {item.name} x {item.qty}</li>{/each}
The key expression allows for efficient adding and removing of items.
{#each users as user (user.id)} <UserCard {user} />{/each}
Text expressions are automatically escaped unless @html
is used.
<p>{string}</p><p>{@html string}</p>
bind:value
forms a two-way binding to a state variable.
<script> let name = '';</script><label> Name: <input bind:value={name} /></label><p>Hello {name || 'stranger'}!</p>
bind:checked
binds the checked state of a checkbox to a state variable.
<script> let subscribed = false;</script><label> <input bind:checked={subscribed} /> Subscribe to the newsletter</label>{#if subscribed} <p>Thank you for subscribing!</p>{/if}
bind:group
binds a variable to a group of elements, such as a radio button group.
<script> let flavor;</script><fieldset> Flavor: <input type='radio' bind:group={flavor} value='vanilla'> <input type='radio' bind:group={flavor} value='mint'></fieldset>
<svelte:head>
allows inserting elements into the document head.
<svelte:head> <meta name="robots" content="noindex"></svelte:head>
<svelte:body>
allows binding DOM events to the body element.
<svelte:body on:mouseenter={handleMouseenter} on:mouseleave={handleMouseleave} use:someAction/>
svelte:window
allows manipulating window properties.
<svelte:window bind:innerWidth={width}/>
innerWidth
innerHeight
outerWidth
outerHeight
scrollX
(rw)scrollY
(rw)online
<svelte:window>
also allows binding DOM events to the window
object.
<svelte:window on:keydown={handleKeydown}/>
Slots allow passing content to a component (“children”).
<script> import Notice from './Notice.svelte'</script><Notice> There will be rain today.</Notice>
<div class='notice'> <strong>Notice:</strong> <slot></slot></div>
Use named slots to pass more than 1 group of children elements.
<MyDialog> <h1 slot='header'>Forecast:</h1> There will be rain today. <div slot='footer'>23°C, Rain</div></MyDialog>
<dialog class='my-dialog'> <header> <slot name='header'></slot> </header>
<slot></slot>
<footer> <slot name='footer'></slot> </footer></dialog>
<svelte:fragment slot="items"> <li>Apple</li> <li>Banana</li> <li>Cherry</li></svelte:fragment>
<slot name="items"></slot>
<slot prop={value}></slot>
<slot prop={value}> This is fallback content</slot>
<script> import { onMount } from 'svelte'; let canvasEl; onMount(() => { drawOn(canvasEl.getContext('2d')); });</script>
<canvas bind:this={canvasEl}></canvas>
Docs: bind:this
I am a web developer helping make the world a better place through JavaScript, Ruby, and UI design. I write articles like these often. If you'd like to stay in touch, subscribe to my list.