Snippets are a useful addition to Svelte 5. I use them in my Svelte 5 projects like
Edna.
Snippet basics
A snippet is a function that renders html based on its arguments.
Here’s how to define and use a snippet:
{#snippet hello(name)}
<div>Hello {name}!</div>
{/snippet}
{@render hello("Andrew")}
{@render hello("Amy")}
You can re-use snippets by exporting them:
<script module>
export { hello };
</script>
{@snippet hello(name)}<div>Hello {name}!</div>{/snippet}
Snippets use cases
Snippets for less nesting
Deeply nested html is hard to read.
You can use snippets to extract some parts to make the structure clearer.
For example, you can transform:
<div>
<div class="flex justify-end mt-2">
<button
onclick={onclose}
class="mr-4 px-4 py-1 border border-black hover:bg-gray-100"
>Cancel</button
>
<button
onclick={() => emitRename()}
disabled={!canRename}
class="px-4 py-1 border border-black hover:bg-gray-50 disabled:text-gray-400 disabled:border-gray-400 disabled:bg-white default:bg-slate-700"
>Rename</button
>
</div>
into:
{#snippet buttonCancel()}
<button
onclick={onclose}
class="mr-4 px-4 py-1 border border-black hover:bg-gray-100"
>Cancel</button
>
{/snippet}
{#snippet buttonRename()}...{/snippet}
To make this easier to read:
<div>
<div class="flex justify-end mt-2">
{@render buttonCancel()}
{@render buttonRename()}
</div>
</div>
snippets replace default <slot/>
In Svelte 4, if you wanted place some HTML inside the component, you used <slot />
.
Let’s say you have Overlay.svelte
component used like this:
<Overlay>
<MyDialog></MyDialog>
</Overlay>
In Svelte 4, you would use <slot />
to render children:
<div class="overlay-wrapper">
<slot />
</div>
<slot />
would be replaced with <MyDialog></MyDialog>
.
In Svelte 5 <MyDialog></MyDialog>
is passed to Overlay.svelte
as children
property so you would change Overlay.svelte
to:
<script>
let { children } = $props();
</script>
<div class="overlay-wrapper">
{@render children()}
</div>
children
property is created by Svelte compiler so you should avoid naming your own props children
.
snippets replace named slots
A component can have a default slot for rendering children and additional named slots.
In Svelte 5 instead of named slots you pass snippets as props.
An example of Dialog.svelte
:
<script>
let { title, children } = $props();
</script>
<div class="dialog">
<div class="title">
{@render title()}
</div>
{@render children()}
</div>
And use:
{#snippet title()}
<div class="fancy-title">My fancy title</div>
{/snippet}
<Dialog title={title}>
<div>Body of the dialog</div>
</Dialog>
passing snippets as implicit props
You can pass title
snippet prop implicitly:
<Dialog>
{#snippet title()}
<div class="fancy-title">My fancy title</div>
{/snippet}
<div>Body of the dialog</div>
</Dialog>
Because {snippet title()}
is a child or <Dialog>
, we don’t have to pass it as explicit title={title}
prop. The compiler does it for us.
snippets to reduce repetition
{#snippet row(name, url, desc)}
<tr>
<td class="text-left align-top"
><a class="font-semibold whitespace-nowrap" href={url}>{name}</a>
</td>
<td class="pl-4 align-top">{@html desc}</td>
</tr>
{/snippet}
{@render row("unzip", "/unzip/", "unzip a file in the browser")}
{@render row("wc", "/wc/", "like <tt>wc</tt>, but in the browser")}
It saves me copy & paste of the same HTML and makes the structure more readable.
snippets for recursive rendering
Sometimes you need to render a recursive structure, like nested menus or file tree.
In Svelte 4 you could use <svelte:self>
but the downside of that is that you create multiple instances of the component. That means that the state is also split among multiple instances.
That makes it harder to implement functionality that requires a global view of the structure, like keyboard navigation.
With snippets you can render things recursively in a single instance of the component.
I used it to implement nested context menus.
snippets to customize rendering
Let’s say you’re building a Menu component. Each menu item is a <div>
with some non-trivial children.
To allow the client of Menu customize how items are rendered, you could provide props for things like colors, padding etc. or you could allow ultimate flexibility by accepting an optional menuitem
prop that is a snippet that renders the item.
You can think of it as a headless UI i.e. you provide the necessary structure and difficult logic like keyboard navigation etc. and allow the client lots of control over how things are rendered.
snippets for library of icons
Before snippets every SVG Icon I used was a Svelte component. Many icons means many files.
Now I have a single Icons.svelte
file, like:
<script module>
export { IconMenu, IconSettings };
</script>
{#snippet IconMenu(arg1, arg2, ...)}
<svg>... icon svg</svg>
{/snippet}}
{#snippet IconSettings()}
<svg>... icon svg</svg>
{/snippet}}