Index of every page on this site: llms.txt
Svelte
Core Concepts

Reactivity in Svelte

In Svelte 5, create one entry with useHead() and patch it from an $effect() that reads your $state() values.

Svelte effects run only in the browser. Pass initial values to useHead() when tags must appear in the server response, then use an effect to patch later client-side changes.

Svelte Integration

The adapter reads the head instance from Svelte context. Each component can create an entry; the adapter disposes it with onDestroy() in the browser.

Reactive Head Tags

Svelte tracks the state read synchronously inside an effect and reruns it when that state changes. Use two steps:

  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({
  title,
  meta: [{ name: 'description', content: `Description for ${title}` }],
})

// Set up the reactive effect
$effect(() => {
  entry.patch({
    title,
    meta: [
      { name: 'description', content: `Description for ${title}` }
    ]
  })
})

function updateTitle() {
  title = 'Updated Title'
}
</script>

<button onclick={updateTitle}>Update Title</button>

Entry Lifecycle

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 })
})

Creating the entry outside the effect avoids adding another entry on every update.

Component Cleanup

The adapter disposes the entry from Svelte's onDestroy hook.

Advanced Usage

Multiple Components

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>

If both components are mounted, ComponentB wins because it mounted last.

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>
Did this page help you?