5 August 2022

A quickdive into Svelte

I've been learning Svelte. Here are my notes as I learned it!

Rico Sta. Cruz @rstacruz

I’ve been learning Svelte. Here are my notes as I learned it! If you’re already familiar with JavaScript and other frameworks, I’m hoping this guide can help you learn Svelte quickly. 👇

Svelte basics

Introduction

Svelte is a web framework for writing rich user interfaces.

Basic component

Svelte components store the markup, script and CSS styles in one .svelte file.

Greeter.svelte
<script>
  let name = "Rico";
</script>
<div>
  hello {name}!
</div>
<style>
  div { color: dodgerblue; }
</style>

Nested components

Using export let will define a component property.

<script>
  import Nested from './Nested.svelte';
</script>
<div>
  My message is:
  <Nested message="Hello there" />
</div>
Nested.svelte
<script>
  export let message;
</script>
<div>
  {message}
</div>
<style>
  div { color: purple; }
</style>

Styling

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 markup

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 -->

State

State & events

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>

Computed state

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>

Reactive statements

$: 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>

Template syntax

If conditionals (#if)

{#if answer === 42}
  Yes
{/if}

Else-if and else (:else)

{#if answer === 42 && a !== b}
  Yes
{:else if answer === 74 || b > c}
  Maybe
{:else}
  No
{/if}

Loops (#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}

Loops with keys

The key expression allows for efficient adding and removing of items.

{#each users as user (user.id)}
  <UserCard {user} />
{/each}

Text markup

Text expressions are automatically escaped unless @html is used.

<p>{string}</p>
<p>{@html string}</p>

Forms

Text inputs

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>

Checkboxes

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}

Radio buttons

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>

Special components

Head elements

<svelte:head> allows inserting elements into the document head.

<svelte:head>
  <meta name="robots" content="noindex">
</svelte:head>

Body events

<svelte:body> allows binding DOM events to the body element.

<svelte:body
  on:mouseenter={handleMouseenter}
  on:mouseleave={handleMouseleave}
  use:someAction
/>

Window props

svelte:window allows manipulating window properties.

<svelte:window
  bind:innerWidth={width}
/>
Properties
  • innerWidth
  • innerHeight
  • outerWidth
  • outerHeight
  • scrollX (rw)
  • scrollY (rw)
  • online

Window events

<svelte:window> also allows binding DOM events to the window object.

<svelte:window
  on:keydown={handleKeydown}
/>

Slots

Slots

Slots allow passing content to a component (“children”).

<script>
  import Notice from './Notice.svelte'
</script>
<Notice>
  There will be rain today.
</Notice>
Notice.svelte
<div class='notice'>
  <strong>Notice:</strong>
  <slot></slot>
</div>

Named slots

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>
MyDialog.svelte
<dialog class='my-dialog'>
  <header>
    <slot name='header'></slot>
  </header>

  <slot></slot>

  <footer>
    <slot name='footer'></slot>
  </footer>
</dialog>

Fragments in named slots

<svelte:fragment slot="items">
  <li>Apple</li>
  <li>Banana</li>
  <li>Cherry</li>
</svelte:fragment>
<slot name="items"></slot>

Slot props

<slot prop={value}></slot>

Slot fallbacks

<slot prop={value}>
  This is fallback content
</slot>

Other features

bind:this

<script>
  import { onMount } from 'svelte';
  let canvasEl;
  onMount(() => {
    drawOn(canvasEl.getContext('2d'));
  });
</script>

<canvas bind:this={canvasEl}></canvas>

Docs: bind:this

Thanks for reading! I'm Rico Sta Cruz, I write about web development and more. Subscribe to my newsletter!