Svelte
Core Concepts

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:

  1. Initialize a head entry using useHead()
  2. 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:

  1. Creating a head instance with Svelte's tick() for DOM updates
  2. Making the head instance available via Svelte's context API
  3. Managing side effects with onDestroy for automatic cleanup
  4. 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.

Did this page help you?