Svelte and SvelteKit course Β· Module 2: Components
Special Svelte Elements
In this lesson6
Svelte offers special elements for handling advanced use cases. Before you meet them - two tricks that needed special elements in Svelte 4, while in Svelte 5 ordinary components do the job.
Recursion - a Component Imports Itself
A component can render itself. In Svelte 5 it simply imports its own file:
<!-- TreeNode.svelte - Branches of Yggdrasil -->
<script>
import TreeNode from './TreeNode.svelte';
let { node, depth = 0 } = $props();
</script>
<div class="node" style="margin-left: {depth * 20}px">
<span>{node.name}</span>
{#if node.children}
{#each node.children as child}
<TreeNode node={child} depth={depth + 1} />
{/each}
{/if}
</div>
<style>
.node {
padding: 0.5rem;
border-left: 2px solid #4a7c23;
}
</style>Usage:
<script>
import TreeNode from './TreeNode.svelte';
const yggdrasil = {
name: 'Yggdrasil',
children: [
{ name: 'Asgard', children: [{ name: 'Valhalla' }] },
{ name: 'Midgard', children: [{ name: 'Svenheim' }] },
{ name: 'Niflheim' }
]
};
</script>
<TreeNode node={yggdrasil} />In Svelte 4 the <svelte:self> element was used for this. In Svelte 5 it is deprecated - the component imports itself.
Dynamic Component
In Svelte 5 components are dynamic on their own: if the variable holding a component changes, Svelte renders the new one. Just store the component in a variable whose name starts with a capital letter and use it like a tag:
<script>
import Warrior from './Warrior.svelte';
import Ship from './Ship.svelte';
import Treasure from './Treasure.svelte';
const components = {
warrior: Warrior,
ship: Ship,
treasure: Treasure
};
let selected = $state('warrior');
let Selected = $derived(components[selected]);
</script>
<select bind:value={selected}>
<option value="warrior">Warrior</option>
<option value="ship">Ship</option>
<option value="treasure">Treasure</option>
</select>
<Selected />In Svelte 4 you had to write <svelte:component this={...} />. In Svelte 5 that element is deprecated.
svelte:element - Dynamic HTML Element
<script>
let { level = 1, text } = $props();
// h1, h2, h3... dynamically
let tag = $derived(`h${Math.min(level, 6)}`);
</script>
<svelte:element this={tag}>
{text}
</svelte:element>svelte:window - Window Events
You attach events to the browser window the same way as to ordinary elements - with attributes such as onkeydown. bind: bindings need variables created with $state:
<script>
let innerWidth = $state(0);
let innerHeight = $state(0);
let scrollY = $state(0);
function handleKeydown(event) {
if (event.key === 'Escape') {
console.log('Escape pressed!');
}
}
</script>
<svelte:window
bind:innerWidth
bind:innerHeight
bind:scrollY
onkeydown={handleKeydown}
/>
<p>Window size: {innerWidth} x {innerHeight}</p>
<p>Scroll: {scrollY}px</p>svelte:document and svelte:body
<script>
function handleVisibility() {
console.log('Tab visibility:', document.visibilityState);
}
function handleMouseEnter() {
console.log('The cursor is back on the page');
}
</script>
<svelte:document onvisibilitychange={handleVisibility} />
<svelte:body onmouseenter={handleMouseEnter} />svelte:head - Meta in head
<script>
let { title = 'Land of the Vikings' } = $props();
</script>
<svelte:head>
<title>{title}</title>
<meta name="description" content="Learning Svelte in the land of the Vikings" />
</svelte:head>Special elements are runes of power for special occasions - reach for them when plain HTML is not enough.
Docs entries used in this lesson
Spotted a mistake in this lesson?
Check yourself
Answer the questions from this lesson. Pick an answer to see right away whether it is correct.
1. How can a component render itself (recursion) in Svelte 5?
2. How do you render a component stored in a variable in Svelte 5?
3. Which special element do we use to modify the page's <head> section?
Hands-on tasks in the game
- Code editor
Complete the code to listen for the keydown event