Skip to content

Instantly share code, notes, and snippets.

@abrman
Last active December 23, 2021 15:36
Show Gist options
  • Save abrman/85c5df229baeea716f2e7ef1528d5b80 to your computer and use it in GitHub Desktop.
Save abrman/85c5df229baeea716f2e7ef1528d5b80 to your computer and use it in GitHub Desktop.
Svelte tutorial notes - cheatsheet

If-else

{#if x > 10}
	{x} is too large!
{:else if 5 > x}
	{x} is perfect
{:else}
	Not sure what you want me to do. >:(
{/if}

For-loop

{#each any[] as foo, index (key)}
	{foo} is at index: {index}
{/each}

Rejectable promise

{#await getRandomNumber()}
	-- getRandomNumber() returns a promise/is async function
{:then number}
	-- {number} is the promise resolution/returned value
{:catch error}
	{error.message} is the error thrown
{/await}

Promise

{#await promise then value}
	<p>the value is {value}</p>
{/await}

DOM Events

<button on:click|trusted={(e) => void }/>

Modifiers:

  • preventDefault — calls event.preventDefault() before running the handler. Useful for client-side form handling, for example.
  • stopPropagation — calls event.stopPropagation(), preventing the event reaching the next element
  • passive — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
  • nonpassive — explicitly set passive: false
  • capture — fires the handler during the capture phase instead of the bubbling phase MDN docs
  • once — remove the handler after the first time it runs
  • self — only trigger handler if event.target is the element itself
  • trusted — only trigger handler if event.isTrusted is true. I.e. if the event is triggered by a user action.

You can chain modifiers together, e.g. on:click|once|capture={...}.

Component Events

Any component can trigger an event using the createEventDispatcher, the parent can handle what happens using the on:eventname={handler} prop.

// App.svelte
<script>
	import Inner from "./Inner.svelte";
</script>
<Inner on:customeventname={(e)=>alert(`Passed: ${e.detail.text}`)}/>
// Inner.svelte
<script>
	import { createEventDispatcher } from 'svelte';
	const dispatch = createEventDispatcher();
</script>
<button on:click={()=>dispatch('customeventname', { text: 'Hello world!' })}>
		Click me!
</button>

View in svelte REPL

Event drilling / forwarding

// App.svelte
<script>
	import Outer from './Outer.svelte';
</script>
<Outer on:click={()=>alert("Root handled click")}/>
// Outer.svelte
<script>
	import Inner from './Inner.svelte';
</script>
<Inner on:click />
// Inner.svelte
<button on:click >Click me!</button>

View in svelte REPL

Binding in form elements

You can bind do any form element in different ways. Radio and Checkbox inputs can utilize groups, you can bind to object values (such as todos.done) or even put a object into the value field. Svelte doesn't mind.

<script>
	let textContent = "Foo";
	let textareaContent = "Bar";
	let checBoxChecked = false;
	let checBoxCheckedValues = ["red"];
	let radioCheckedValue = null;
	let todos = [
		{id: 1, content: "Eat", done: false},
		{id: 2, content: "Work", done: false},
		{id: 3, content: "Sleep", done: false}
	];
	let selectedPeople = [];
</script>

<input bind:value={textContent} type=text />

<textarea bind:value={textareaContent}></textarea>

<label>
	<input bind:checked={checBoxChecked} type=checkbox /> Checkbox
</label>

{#each ["red","green","blue"] as color}
	<label>
		<input bind:group={checBoxCheckedValues} type=checkbox value={color} /> {color}
	</label>
{/each}

{#each ["red","green","blue"] as color}
	<label>
		<input bind:group={radioCheckedValue} type=radio value={color} /> {color}
	</label>
{/each}

{#each todos as todo (todo.id)}
	<label>
		<input bind:checked={todo.done} type=checkbox /> {todo.content}
	</label>
{/each}

<select multiple bind:value={selectedPeople}>
	{#each [{name: "Mark", age: 28},{name:"Matt", age: 27}] as person}
		<option value={person}>
			{person.name}
		</option>
	{/each}
</select>

View in svelte REPL

Binding to DOM

// ContenteditableBind.svelte
<script>
	let html = '<p>Write text!</p>';
</script>
<div contenteditable="true" bind:innerHTML={html} />
// ReadonlyBinds.svelte
<script>
	let [w,h,ow,oh] = [0,0,0,0]
</script>
<div bind:clientWidth={w} bind:clientHeight={h} bind:offsetWidth={ow} bind:offsetHeight={oh}>
// ThisBind.svelte
<script>
	import { onMount } from 'svelte';
	let canvas;
	onMount(() => {
		let frame = requestAnimationFrame(loop);
		const loop = (timestamp) => {
			frame = requestAnimationFrame(loop);
			...
		}
		return () => cancelAnimationFrame(frame);
	});
</script>
<canvas bind:this={canvas} .../>

Binding component props

// ComponentBinding.svelte
<script>
	import Keypad from "./Keypad.svelte"; 
	let pin = "";
</script>
<Keypad bind:value={pin} on:submit={handleSubmit}/>
// Keypad.svelte
<script>
	export let value = 'default value';
</script>	

Keypad can update parents pin variable without dispatching any events. View in svelte REPL

Lifecycle hooks

Lifecycle hooks take one argument, a callback function, and can only be called at root level of a component with the exception of tick;

  • onMount - return of onMount is cleanup, similar to useEffect from React
  • onDestroy - runs before component unmounts
  • beforeUpdate - runs before DOM updates with updated data
  • afterUpdate - runs after DOM updates with new data
  • tick - if you need for DOM to update with new data, you can do so with await tick();
import { 
	onMount,
	onDestroy, 
	beforeUpdate,
	afterUpdate, 
	tick
} from 'svelte';

Store subscriptions - basically react context

//stores.js
import { writable } from 'svelte/store';
export const count = writable(0);
// StoreReader.svelte -- subscribe method and returned unsubscribe value
<script>
	import { onDestroy } from 'svelte';
	import { count } from './stores.js';
	const unsubscribe = count.subscribe(value => {
		console.log("Value updated to: " + value)
	});
	onDestroy(unsubscribe);
</script>
// StoreWriter.svelte
<script>
	import { count } from './stores.js';
	count.update(prevValue => prevValue + 1);
	count.set(0);
</script>

Store auto-subscription & binding

You can use auto-subsciptions by prepending $ to the store variable. $ is a reserved character and no other variables can begin with $ in svelte.

// store.js
import { writable } from 'svelte/store';
export const count = writable(0);
// StoreReader.svelte
<script>
	import { count } from './store.js';
</script>
<h1>The current count is {$count}</h1>
<button on:click={()=>$count++}>Increment count</button>

View in svelte REPL

Read-only store

readable()'s first parameter is the initial value, the second parameter is the start callback, which is called with the first subscriber to the value, and the starts's return function end is called whenever subscriber count goes back to 0,

Official docs on readable

// stores.js
import { readable } from 'svelte/store';
export const time = readable(new Date(), function start(set) {
	const interval = setInterval(() => {
		set(new Date());
	}, 1000);

	return function stop() {
		clearInterval(interval);
	};
});

Reducer like store

// count.js
import { writable } from 'svelte/store';
const { subscribe, set, update } = writable(0);
export const count = {
	subscribe,
	increment: () => update(n => n + 1),
	decrement: () => update(n => n - 1),
	reset: () => set(0)
};

Derived store

Official docs on derived

derived at it's simplest form has a single dependency which should be the first parameter of the function, this dependency is then passed into the 2nd parameter - the callback function, which should return the new derived value.

derived(dep, $dep => $dep / 2 )

If there are multiple dependencies, you put them into an array and pass it as 1st parameter of derived, the callback now passes an array of these dependencies as 1st parameter of the callback function.

derived([dep_a, dep_b], ([$dep_a, $dep_b]) => $dep_a + $dep_b);

And finally if called similarly to readable, you can call the start callback which passes the value setter as first prop, and you return end just as with readable. The difference however is that end and start are re-called again whenever the dependency changes.

// timeStore.js
import { readable, derived } from 'svelte/store';

const initialTime = new Date();
export const time = readable(initialTime, function start(set){
	const interval = setInterval(() => set(new Date()), 1000);
	return function stop() {
		clearInterval(interval);
	};
});

export const elapsed = derived(	time, $time => 
	Math.round( ($time - initialTime) / 1000)
);

Tween and Spring on variables

Svelte will interpolate between numbers, dates, and identically-shaped arrays and objects (as long as they only contain numbers and dates or other valid arrays and objects). If you want to interpolate (for example) colour strings or transformation matrices, supply a custom interpolator.

There are further options you can specift with tweened and spring that this demo covers.

//LinearTween.svelte
<script>
	import { tweened } from 'svelte/motion';
	const progress = tweened(0);
</script>
//EasedTween.svelte
<script>
	import { tweened } from 'svelte/motion';
	import { cubicOut } from 'svelte/easing';
	const progress = tweened(0, {
		duration: 400,
		easing: cubicOut
	});
</script>

Official docs on tweened

//BasicSpring.svelte
<script>
	import { spring } from 'svelte/motion';
	let value = spring(10);
</script>
//ConfiguredSpring.svelte
<script>
	import { spring } from 'svelte/motion';
	let coords = spring({ x: 50, y: 50 }, {
		stiffness: 0.1,
		damping: 0.25
	});
	let size = spring(10);
</script>

Official docs on spring

Transition

Blink in svelte with transitions. Main part is transition:fade on DOM element.

<script>
	import { onMount} from 'svelte';
	import { fade } from 'svelte/transition';
	let visible = true;
	onMount( () => {
		const interval = setInterval(() => visible = !visible, 1000 );
		return () => clearInterval(interval)
	})
</script>
{#if visible}
	<p transition:fade> Fades in and out </p>
{/if}

You can also use fly:

<script>
	import { fly } from 'svelte/transitions';
</script>
<p transition:fly={{ y: 50, duration: 200}}> Flies in and out </p>

Or you can specify transition-in and out respectively:

<p in:fly={{ y: 200, duration: 2000 }} out:fade>
	Flies in, fades out
</p>

Transition docs for more:

Custom transition functions

Custom animate functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment