---
title: useHead()
description: API reference for the useHead composable.
---

The `useHead()`{lang="ts"} composable is for managing the document head. It provides a type-safe, reactive API to define, update, and remove head elements like title, meta tags, scripts, and more. It's the core composable used across all frameworks in the Unhead ecosystem.

```ts
import { useHead } from '@unhead/dynamic-import'

const entry = useHead({
  title: 'My Page',
})
// update
entry.patch({ title: 'new Title' })
// remove
entry.dispose()
```

### How It Works

The composable works by queuing your input to be resolved when the head is rendered:

1. It registers your head configuration in a queue
2. When the document head is being rendered (client-side or during SSR), all queued entries are:
   - Resolved (including any functions, promises or reactive values)
   - Deduplicated (removing redundant tags) - see [Handling Duplicates](/guides/handling-duplicates)
   - Sorted (based on tag priority) - see [Tag Positions](/guides/positions)
   - Merged when appropriate
3. The resolved tags are then rendered to the document head

This queue-based approach enables powerful features like deduplication, async resolution, and priority-based rendering while maintaining optimal performance.

::note
You won't know the final state of the head until the rendering is complete.
::

### Reactivity Model

`useHead()`{lang="ts"} provides reactivity through two main mechanisms:

1. **Framework Integration**: When used with frameworks it automatically integrates with the framework's reactivity system
2. **Manual API**: The returned `ActiveHeadEntry` object with `patch()` and `dispose()` methods lets you manually update or remove head entries

## API Reference

```ts
function useHead(input: UseHeadInput, options?: HeadEntryOptions): ActiveHeadEntry
```

### Parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `input` | `Head` | Yes | The head configuration object |
| `options` | `HeadEntryOptions` | No | Configuration options for the head entry |

### Returns

```ts
interface ActiveHeadEntry {
  /**
   * Update the head entry with new values
   */
  patch: (input: Partial<UseHeadInput>) => void
  /**
   * Remove the head entry
   */
  dispose: () => void
}
```

## Input Schema

The input object accepts the following properties:

```ts
interface Head<E extends MergeHead = SchemaAugmentations> {
  // Document title
  title?: string | Promise<string>

  // Title template (function or string with %s placeholder)
  titleTemplate?: string | null | ((title?: string) => string | null)

  // Template parameters for dynamic replacements
  templateParams?: { separator?: string } & Record<string, string | Record<string, string>>

  // HTML tag collections
  base?: Base<E['base']>
  link?: Link<E['link']>[]
  meta?: Meta<E['meta']>[]
  style?: (Style<E['style']> | string)[]
  script?: (Script<E['script']> | string)[]
  noscript?: (Noscript<E['noscript']> | string)[]

  // Element attributes
  htmlAttrs?: HtmlAttributes<E['htmlAttrs']>
  bodyAttrs?: BodyAttributes<E['bodyAttrs']>
}
```

The input is deeply resolved allowing you to provide any value as a function. This can be useful
for lazily resolving values when the head tags are being rendered.

::tip
Lazy resolving values can improve performance for complex or computed values that aren't needed until the head is actually rendered.
::

```ts
import { useHead } from '@unhead/dynamic-import'

const title = useMyTitle()
useHead({
  // just works
  title: () => 'Dynamic Title',
  meta: [
    () => ({
      name: 'description',
      content: () => `Description for ${title.value}`
    }),
  ]
})
```

## Options

The `options` parameter allows you to configure the behavior of the head entry:

```ts
export interface HeadEntryOptions {
  // Whether to process template parameters in the input
  // - Requires the TemplateParams plugin
  processTemplateParams?: boolean

  // Priority of tags for determining render order
  tagPriority?: number | 'critical' | 'high' | 'low' | `before:${string}` | `after:${string}`

  // Where to position tags in the document
  tagPosition?: 'head' | 'bodyClose' | 'bodyOpen'

  // Custom head instance
  head?: Unhead
}
```

Setting any of these will apply that rule to all tags within the entry. For example if we want to push several meta tags
with low priority, we can do:

::tip
Learn more about using [Tag Priorities](/guides/positions) and [Template Parameters](/plugins/template-params) in their dedicated guides.
::

```ts
import { useHead } from '@unhead/dynamic-import'

useHead({
  meta: [
    { name: 'description', content: 'fallback description' },
    { name: 'author', content: 'fallback author' }
  ]
}, {
  tagPriority: 'low'
})
```

::note
The `tagPriority`{lang="ts"} option is particularly useful for controlling render order when you have multiple head entries that might contain similar tags.
::

## Reactivity

::VueOnly

### Automatic Reactivity

The `useHead()`{lang="ts"} composable automatically integrates with your framework's reactivity system:

```ts
// Vue example with reactive data
import { useHead } from '@unhead/dynamic-import'
import { computed, ref } from 'vue'

const title = ref('Dynamic Title')

useHead({
  title,
  meta: [
    { name: 'description', content: computed(() => `Description for ${title.value}`) }
  ]
})
```

Framework integrations like Vue automatically:
- Track reactive data changes with `watchEffect`
- Resolve refs, computed props, and reactive objects
- Clean up head entries on component unmount
- Handle special cases like keep-alive components

::

### Manual Control

For more granular control, you can use the returned API:

```ts
import { useHead } from '@unhead/dynamic-import'

// Create the head entry
const headControl = useHead({
  title: 'Initial Title'
})

// Later update specific fields
headControl.patch({
  title: 'Updated Title',
  meta: [
    { name: 'description', content: 'New description' }
  ]
})

// Remove the entry entirely when needed
headControl.dispose()
```

**Use cases for manual control:**
- Updating head after asynchronous data loading
- Conditional changes based on user interactions
- Managing head from global state
- Creating temporary modifications

For framework-specific reactivity details, see the guides for each specific framework.

## Security Considerations

::warning
The `useHead()`{lang="ts"} function applies minimal sanitization to improve developer experience.

**Do not** use this function with untrusted or third-party input. It cannot guarantee safety when handling unknown content.
::

For XSS protection, either:
1. Sanitize your input before passing it to `useHead()`{lang="ts"}
2. Use the safer alternatives:
   - [useSeoMeta()](/docs/head/api/composables/use-seo-meta) for SEO metadata
   - [useHeadSafe()](/docs/head/api/composables/use-head-safe) for general head management

## Advanced Examples

### Title Template

```ts
import { useHead } from '@unhead/dynamic-import'

useHead({
  titleTemplate: title => `${title} - My Site`,
  title: 'Home Page'
})
// Results in: "Home Page - My Site"
```

For more details on title templates, see the [Titles guide](/guides/titles).

### Combining Multiple Head Entries

```ts
import { useHead } from '@unhead/dynamic-import'

// Global site defaults
useHead({
  titleTemplate: '%s | My Website',
  meta: [
    { name: 'og:site_name', content: 'My Website' }
  ]
})

// Page-specific entries (will be merged with globals)
useHead({
  title: 'Product Page',
  meta: [
    { name: 'description', content: 'This product is amazing' }
  ]
})
```

::tip
This pattern is commonly used to implement layouts with defaults and page-specific overrides.
::

### Async Data Loading

```ts
import { useHead } from '@unhead/dynamic-import'
import { computed, ref } from 'vue'

// Initial setup
const data = ref(null)
const loading = ref(true)
const error = ref(null)

const headControl = useHead({
  title: computed(() => data.value
    ? `${data.value.name} - Product`
    : loading.value
      ? 'Loading...'
      : 'Product Not Found')
})

// Fetch data and update head
async function fetchProduct(id) {
  try {
    loading.value = true
    data.value = await api.getProduct(id)
  }
  catch (err) {
    error.value = err
  }
  finally {
    loading.value = false
  }
}
```

::note
This pattern works well with data fetching libraries and state management solutions.
::

### Priority-Based Tag Ordering

```ts
import { useHead } from '@unhead/dynamic-import'

// Critical meta tags (early in <head>)
useHead({
  meta: [
    { charset: 'utf-8' },
    { name: 'viewport', content: 'width=device-width, initial-scale=1' }
  ]
}, { tagPriority: 'critical' })

// Default priority tags (middle of <head>)
useHead({
  meta: [
    { name: 'description', content: 'My website description' }
  ]
})

// Low priority tags (end of <head>)
useHead({
  meta: [
    { name: 'author', content: 'Jane Doe' }
  ]
}, { tagPriority: 'low' })
```

## Common Use Cases

Here are some common use cases for `useHead()`{lang="ts"}:

- Setting page-specific metadata for SEO (consider using [useSeoMeta()](/docs/head/api/composables/use-seo-meta) for a more convenient API)
- Managing document title and favicon (see [Titles guide](/guides/titles))
- Adding external scripts and stylesheets (consider using [useScript()](/docs/head/api/composables/use-script) for scripts)
- Setting Open Graph and Twitter card tags

For ready-to-use implementations of common patterns, see our [Starter Recipes](/guides/starter-recipes).