Welcome,
this is the second part of our amazing Svelte journey. Previously, we’ve learned about the basics, template and reactivity. Today, we'll delve into Props, Template Directives, and Events. So, let’s start.
Props
⚠️ export
keyword is not regular JS export
export
marks that a variable is an external, input property.
<script>
export let foo; // 'export' means input prop
export let marko = 'Polo'; // input prop with default value
</script>
{…spread} props
Pretty same as in React:
<PackageInfo
name={pkg.name}
speed={pkg.speed}
version={pkg.version}
website={pkg.website}
/>
<PackageInfo {...pkg} />
$$props — last resort stuff 🚩
Is needed for reference all props (including also properties, that were not mentioned as inputs (export let <prop name>
) for the component).
- Feels like
(…props: any[])
or JS function’sarguments
; -
$$restProps
allows to do the same but only for props, that were not mentioned as inputs; - Not recommended, difficult for Svelte to optimise.
Template Directives
// Conditional rendering
{#if count > 10}
<p>{count} is greater than 10</p>
{:else if count < 5}
<p>{count} is less than 5</p>
{:else}
<p>{count} is between 5 and 10</p>
{/if}
// Iterables (any generic iterables) rendering
{#each colors as color, i (color)} // ", i" is optional; (*) is key, also optional
<span>{color}, idx: {i}</span>
{/each}
Key
for lists rendering
- similar to other libs/frameworks, optimises DOM updates;
- any object can be
key
, but string or number is safer. So keep it safe.
// Key usage samples
{#each things as thing, i (thing.id)}
<Thing name={thing.name + " - " + i} />
{/each}
{#each things as thing, i (i)}
<Thing name={thing.name + " - " + i} />
{/each}
await
blocks for async operations 🍭
- Kinda
async
pipe from Angular oruseQuery
from tanstack's library - Only the most recent promise is considered — new value comes into variable and cancels previous pending state if some.
// Basic async stuff
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
// if you're sure there are no rejects
{#await promise then number}
<p>The number is {number}</p>
{/await}
Events
<script>
let m = { x: 0, y: 0 };
function handleMove(event) {
m.x = event.clientX;
m.y = event.clientY;
}
</script>
<div
on:pointermove={handleMove} // Handler fn.
on:click={(e) => { // Inline handler
console.log(m, e.target);
}}
>
The pointer is at {m.x} x {m.y}
</div>
Modifiers
for event handlers 🍰
Pipelike handy notation to apply modifiers:
<button on:click|once={() => alert('clicked')}>
Click me
</button>
<button on:click|once|self|capture={() => alert('you can chain them!')}>
Click me
</button>
Available modifiers:
-
preventDefault
; -
stopPropagation
; -
passive
— about scrolling. Svelte handles it automatically; -
nonpassive
— explicitly set passive: falsecapture
; -
once
; -
self
— only trigger handler if event.target is the element itself; -
trusted
— only trigger handler if event.isTrusted is true, meaning it is a action performed by human (click) rather than by code.
Component events
You need to:
- have a name for an event;
- dispatch this event via special dispatcher service, that is provided by svelte;
- assign to events and handle them.
Here is a simple example:
// Inner.svelte --------------------------------------------------------------
<script>
import { createEventDispatcher } from 'svelte'; // the service
const dispatch = createEventDispatcher(); // we created dispatcher
function doSomething() {
dispatch('somethingHappened', { // dispatch 'somethingHappened' event
action: 'You did it!'
});
}
</script>
<button on:click={doSomething}> // click will trigger event dispatch
Do it.
</button>
// Outer.svelte --------------------------------------------------------------
...
<Inner on:somethingHappened={handleEvent} /> // listen to an event
...
And this example is more broad, it depicts how you can forward dispatches and how to handle not only component events, but also DOM events:
// App.svelte ------------------------------------------------------------
<script>
import Outer from './Outer.svelte';
import CustomButton from './CustomButton.svelte';
function handleMessage(event) {
alert(event.detail.action);
}
function handleClick(event) {
alert("Polo!");
}
</script>
<Outer on:somethingHappened={handleMessage} />
<CustomButton on:click={handleClick} />
// Outer.svelte ------------------------------------------------------------
<script>
import Inner from './Inner.svelte';
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function forward(e) {
dispatch('somethingHappened', e.detail);
}
</script>
<Inner on:somethingHappened={forward} />
// Inner.svelte ------------------------------------------------------------
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function doSomething() {
dispatch('somethingHappened', {
action: 'And something happened!'
});
}
</script>
<button on:click={doSomething}>
Time has come
</button>
// CustomButton.svelte -------------------------------------------------------
<script>
import { createEventDispatcher } from 'svelte';
const dispatch = createEventDispatcher();
function forwardClick(e) {
dispatch('click', e)
}
</script>
<button on:click={forwardClick}>
Marko
</button>
<style>
button {
background: navajowhite;
padding: 4px 8px;
}
</style>
-
createEventDispatcher
must be called at the initialisation; - component events don't bubble — you need to forward them;
- DOM event forwarding — the same as component’s events.
Amazing REPL, Amazing CLI
The code snippets quickly outgrew the tutorial's IDE, prompting me to seek alternatives. I turned to the Svelte REPL, an online environment that seemed perfect and even offered PWA installation. However, my intention was to experiment without registration, which unfortunately wasn't allowed.
Undeterred, I chose to download it locally using npm create svelte@latest my-app
, and the experience was remarkably convenient 🏅. However, my initial excitement dwindled when npm install raised concerns about broken dependencies. While forcing it was an option, opting for stability with a non-beta version proved to be the solution. It serves as a valuable reminder that only reliable components should make their way into production.
In the end, everything is running smoothly.
Take care, go Svelte!
Top comments (3)
Thank you for a very informative Sveltekit series. I've learnt a lot.
When doing multiple parts of a topic, you are best off with the Series feature of Dev.to.
Hey José,
Thanks a bunch for the hint! Got it fixed.