Skip to main content

Svelte Concepts

Basics

Variables

https://svelte.dev/docs/svelte/$state

https://svelte.dev/docs/svelte/$derived

let state_var = $state(start_value)
let derived_var = $derived(state_var * 2)
let derived_var_by_func = $derived.by(() => {
  // For more complicated logic
  return state_var * 2
)

Apparently you should prefer to use $derived over $effect because DOM changes should not be done in $effect. $effect is run after the DOM has changed. Use $effect.pre if you want to mutate a variable before DOM update (only use this rarely).

Inside $derived or $effect if you want to not have a variable as dependency, use untrack

$effect.pre(() => {
    // Stop tracking 'last_scroll' to not retrigger this $effect
    const previousScroll = untrack(() => last_scroll)
    show_nav = scrollY.current! === 0 || scrollY.current! < previousScroll
    // Save last frame's Y-scroll-position
    last_scroll = scrollY.current!
})

Bind values to variables

https://svelte.dev/docs/svelte/bind

You can bind values directly to input elements, so that the variable changes when the input value changes.

This can be done on text inputs, number inputs, checkbox inputs.

let value = $state(1)
<input type="number" bind:value={message} />

You can also use function bindings to use getters and setters.

Props

https://svelte.dev/docs/svelte/$props

Props are used on children components. Parent components can instanciate children components with arguments.

Values should always be changed in the parent element (TODO why?), so pass down functions to the children to allow value mutation. Sometimes, the displayed values are mapped or filtered values, so the mutation should not be done on the props directly.

let {my_prop1, my_prop2}: {my_prop1: my_prop1_type, my_prop2: my_prop2_type} = $props()

Use components like this:

<MyComponent my_prop1="value" my_prop2={1+1} />
<MyComponent {...my_prop1, my_prop2} />

Bindable props

If you want to change variables/data in the parent component from the child component, you will need to use $bindable

let {my_prop1 = $bindable(), my_prop2}: {my_prop1: my_prop1_type, my_prop2: my_prop2_type} = $props()

The parent Component needs to instantiate the Child with:

<MyComponent bind:my_prop1={my_prop1} />

Or simply

<MyComponent bind:my_prop1 />

If else

https://svelte.dev/docs/svelte/if

TODO

Each

https://svelte.dev/docs/svelte/each

TODO

Intermediate

Stores

To have access to a variable across multiple components without using props (e.g. global app state like language setting), you can use stores.

Strategically wise would be to have it divided into two files:

  • persistent store (using local storage)
  • temporary store (state gets reset on page reload)
import { writable } from 'svelte/store'
type Language = "de" | "en"
const storage = {
	"app_language": writable<Language>("en"),
}
export const app_language = storage.app_language

These stores can also be bound and used as props

<script lang="ts">
	import { app_language } from '$lib/persistent-store'
</script>

<select bind:value={$app_language}>
    <option value="de">Deutsch</option>
    <option value="en">English</option>
</select>

See advanced examples here and here

Snippets

Prefer snippets over components if they aren't being reused anywhere else. This way they have access to the same variables without the need of props drilling.

Define a snippet with

{#snippet snippet_name(snippet_arg: snippet_arg_type, ...)}
  <div>{snippet_arg}</div>
{/snippet}

Use snippet with

{@render snippet_name('my_value')}

Classes on condition

https://svelte.dev/docs/svelte/class

You can use classes on elements conditionally

<script>
	let my_boolean = $state(true)
</script>

<div 
  class={["this class is always applied", {"this class is applied if the condition is true": my_boolean}]}
>
  My Text
</div>

Advanced

Debugging

You can use https://svelte.dev/docs/svelte/$inspect to console log values when they change.

let my_var = $state(1)
$inspect(my_var)

Transition and animation

A transition is triggered by an element entering or leaving the DOM as a result of a state change.

https://svelte.dev/docs/svelte/transition

https://svelte.dev/docs/svelte/svelte-transition

<div transition:fade>fades in and out</div>

https://svelte.dev/docs/svelte/in-and-out

If you want more control over the transition, you can directly define the in and out transition, instead of using one transition for in and the reverse for out transition

<div in:fly={{ y: 200 }} out:fade>flies in, fades out</div>

https://svelte.dev/docs/svelte/animate

https://svelte.dev/docs/svelte/svelte-animate

An animation is triggered when the contents of a keyed each block are re-ordered. Animations do not run when an element is added or removed, only when the index of an existing data item within the each block changes.