Reactivity in Svelte
Introduction
Unhead integrates with Svelte's reactivity system through the Svelte context API. This guide explains how to effectively manage reactive head tags in your Svelte applications.
How Unhead Works in Svelte
Unhead registers itself in the Svelte context, making head management available throughout your component tree. Each component can create head entries that automatically clean up when the component is destroyed.
Creating Reactive Head Tags
Svelte doesn't support reactivity outside of components. To create reactive head tags, you need to:
- Initialize a head entry using
useHead()
- Use the returned
patch()
function within a Svelte$effect
to update when state changes
Basic Pattern
<script lang="ts">
import { useHead } from '@unhead/svelte'
// Reactive state
let title = $state('My Page Title')
// Create a head entry instance
const entry = useHead()
// Set up the reactive effect
$effect(() => {
entry.patch({
title,
meta: [
{ name: 'description', content: `Description for ${title}` }
]
})
})
function updateTitle() {
title = 'Updated Title'
}
</script>
<button on:click={updateTitle}>Update Title</button>
Best Practices
Initialize Once, Patch Often
Create the head entry once, outside of the effect, and use patch()
within the effect:
// ✅ Good: Create entry once
const entry = useHead()
$effect(() => {
entry.patch({ title })
})
// ❌ Avoid: Creating new entry on each update
$effect(() => {
useHead({ title })
})
This pattern prevents unnecessary memory allocations and ensures proper cleanup.
Component Cleanup
Unhead automatically handles cleanup when a component is unmounted. The onDestroy
lifecycle hook is used internally to dispose of head entries when the component is removed from the DOM.
Advanced Usage
Multiple Counters Example
When multiple components modify the same head properties, Unhead handles priorities based on mount order (later components have higher priority):
<!-- ComponentA.svelte -->
<script>
import { useHead } from '@unhead/svelte'
let count = $state(0)
const entry = useHead()
$effect(() => {
entry.patch({
title: `Count A: ${count}`
})
})
</script>
<!-- ComponentB.svelte -->
<script>
import { useHead } from '@unhead/svelte'
let count = $state(0)
const entry = useHead()
$effect(() => {
entry.patch({
title: `Count B: ${count}`
})
})
</script>
In this example, ComponentB's title will be shown if both components are mounted, as it was mounted last.
Using Other Composables
The same reactivity pattern applies to other Unhead composables:
<script>
import { useSeoMeta } from '@unhead/svelte'
let title = $state('My Page')
let description = $state('Page description')
const entry = useSeoMeta()
$effect(() => {
entry.patch({
title,
description
})
})
</script>
Implementation Details
Unhead in Svelte works by:
- Creating a head instance with Svelte's
tick()
for DOM updates - Making the head instance available via Svelte's context API
- Managing side effects with
onDestroy
for automatic cleanup - Using
$effect
to track state changes and update head entries
This integration ensures that your head tags stay in sync with your component state while maintaining performance.