unhead@betaQuick Answer: Template params let you use placeholders like %s and %siteName in your head tags. Configure them with templateParams: { siteName: 'My Site', separator: '·' } in useHead().
The Template Params plugin lets you define variables that can be used across your meta tags. While you could use functions for dynamic content, template params work better with SSR and avoid hydration issues.
Add the plugin to your Unhead configuration:
import { createHead } from 'unhead'
import { TemplateParamsPlugin } from 'unhead/plugins'
const head = createHead({
plugins: [
TemplateParamsPlugin()
]
})
Unhead includes two built-in template params:
| Token | Description |
|---|---|
%s | The current page title |
%separator | Smart separator (defaults to |) |
The %separator is intelligent - it only appears between content and removes itself when:
useHead({
title: 'Home',
titleTemplate: '%s %separator %siteName',
templateParams: {
separator: '—', // Use an em dash instead of |
siteName: 'MySite'
}
})
<title>Home — MySite</title>
For better readability, consider these separator alternatives:
// Choose a more readable separator
useHead({
templateParams: {
separator: '—' // Em dash
// Other options: '-' (hyphen), '•' (bullet), '·' (middot), '❤️' (heart)
}
})
Template params work seamlessly with SEO meta tags and social sharing:
useHead({
templateParams: {
siteName: 'MyApp',
separator: '·'
},
title: 'Home',
meta: [
{ name: 'description', content: 'Welcome to %siteName - where we make awesome happen' },
{ property: 'og:title', content: 'Home %separator %siteName' },
{ property: 'og:description', content: 'Check out %siteName today!' }
]
})
<head>
<title>Home · MyApp</title>
<meta name="description" content="Welcome to MyApp - where we make awesome happen">
<meta property="og:title" content="Home · MyApp">
<meta property="og:description" content="Check out MyApp today!">
</head>
For tags using innerHTML or textContent, add processTemplateParams: true:
useHead({
templateParams: { name: 'My App' },
script: [
{
innerHTML: { name: '%name' },
type: 'application/json',
processTemplateParams: true
}
]
})
<script type="application/json">{ "name": "My App" }</script>
Add processTemplateParams: false to skip template processing:
useHead({
title: 'Hello %name',
templateParams: { name: 'World' },
}, {
processTemplateParams: false,
})
<title>Hello %name</title>
Maintain consistent branding across your site:
// In your site setup
const head = createHead({
plugins: [
TemplateParamsPlugin()
]
})
// Define global template params
head.push({
templateParams: {
brand: 'ProductName™',
tagline: 'The best solution for your needs',
separator: '—'
}
})
// In page components
useHead({
title: 'Features',
titleTemplate: '%s %separator %brand',
meta: [
{ name: 'description', content: '%brand: %tagline' }
]
})
Use nested objects for more structured data:
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',
},
],
})
<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>