---
title: "Template Params Plugin"
description: "Dynamic placeholders like %s and %siteName in head tags. Define site name, separator, and custom variables for consistent branding."
canonical_url: "https://unhead.unjs.io/docs/head/guides/plugins/template-params"
last_updated: "2026-08-03T02:21:33.126Z"
---

Template params replace placeholders such as `%s` and `%siteName` during tag resolution. Configure them with `templateParams: { siteName: 'My Site', separator: '·' }` in `useHead()`.

## Template params

The Template Params plugin replaces named placeholders across titles and tag properties during head resolution.

## Setup

Add the plugin to your Unhead configuration:

<code-block>

```ts [Input]
import { createHead } from '@unhead/dynamic-import/client'
import { TemplateParamsPlugin } from '@unhead/dynamic-import/plugins'

const head = createHead({
  plugins: [
    TemplateParamsPlugin
  ]
})
```

</code-block>

## Built-in params

Unhead includes these built-in template params:

<table>
<thead>
  <tr>
    <th>
      Token
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        %s
      </code>
    </td>
    
    <td>
      The current page title
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        %pageTitle
      </code>
    </td>
    
    <td>
      Alias for the current page title
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        %separator
      </code>
    </td>
    
    <td>
      Smart separator (defaults to |)
    </td>
  </tr>
</tbody>
</table>

`%separator` appears only between non-empty content. It removes itself when:

- The title is empty
- Multiple separators would appear next to each other

<code-block>

```ts [Input]
useHead({
  title: 'Home',
  titleTemplate: '%s %separator %siteName',
  templateParams: {
    separator: '—', // Use an em dash instead of |
    siteName: 'MySite'
  }
})
```

```html [Output]
<title>Home — MySite</title>
```

</code-block>

## Separators

Choose a separator that matches the site's title style:

<code-block>

```ts [Input]
// Choose a more readable separator
useHead({
  templateParams: {
    separator: '—' // Em dash
    // Other options: '-' (hyphen), '•' (bullet), '·' (middot), '❤️' (heart)
  }
})
```

</code-block>

## Meta tags

Template params also work with [SEO meta tags](/docs/head/api/composables/use-seo-meta) and social metadata:

<code-block>

```ts [Input]
useHead({
  templateParams: {
    siteName: 'MyApp',
    separator: '·'
  },
  title: 'Home',
  meta: [
    { name: 'description', content: 'Read the latest updates from %siteName' },
    { property: 'og:title', content: 'Home %separator %siteName' },
    { property: 'og:description', content: 'Check out %siteName today!' }
  ]
})
```

```html [Output]
<head>
  <title>Home · MyApp</title>
  <meta name="description" content="Read the latest updates from MyApp">
  <meta property="og:title" content="Home · MyApp">
  <meta property="og:description" content="Check out MyApp today!">
</head>
```

</code-block>

## Scripts and other inline content

### Enable for Script and Other Tags

For tags using `innerHTML` or `textContent`, add `processTemplateParams: true`:

<code-block>

```ts [Input]
useHead({
  templateParams: { name: 'My App' },
  script: [
    {
      innerHTML: { name: '%name' },
      type: 'application/json',
      processTemplateParams: true
    }
  ]
})
```

```html [Output]
<script type="application/json">{"name":"My App"}</script>
```

</code-block>

### Disabling template processing

Add `processTemplateParams: false` to skip template processing:

<code-block>

```ts [Input]
useHead({
  title: 'Hello %name',
  templateParams: { name: 'World' },
}, {
  processTemplateParams: false,
})
```

```html [Output]
<title>Hello %name</title>
```

</code-block>

## Shared and nested values

### Shared brand values

Define shared brand values once, then reference them from page entries:

<code-block>

```ts [Input]
// In your site setup
const head = createHead({
  plugins: [
    TemplateParamsPlugin
  ]
})

// Define global template params
head.push({
  templateParams: {
    brand: 'ProductName™',
    tagline: 'Release notes and migration guides',
    separator: '—'
  }
})

// In page components
useHead({
  title: 'Features',
  titleTemplate: '%s %separator %brand',
  meta: [
    { name: 'description', content: '%brand: %tagline' }
  ]
})
```

</code-block>

### Nested objects

Use nested objects for more structured data:

<code-block>

```ts [Input]
useHead({
  templateParams: {
    site: {
      name: 'My Site',
      url: 'https://example.com',
    },
    separator: '·',
    subPage: null
  },
  title: 'My Page',
  titleTemplate: '%s %separator %subPage %separator %site.name',
  meta: [
    {
      name: 'description',
      content: 'Welcome to %site.name.',
    },
    {
      property: 'og:site_name',
      content: '%site.name',
    },
    {
      property: 'og:url',
      content: '%site.url/my-page',
    },
  ],
})
```

```html [Output]
<head>
<title>My Page · My Site</title>
<meta name="description" content="Welcome to My Site.">
<meta property="og:site_name" content="My Site">
<meta property="og:url" content="https://example.com/my-page">
</head>
```

</code-block>

## Related

- [Canonical Plugin](/docs/head/guides/plugins/canonical): Normalize absolute URLs
- [Infer SEO Meta](/docs/head/guides/plugins/infer-seo-meta-tags): Generate social metadata
