Template Params

Template params let you use variables in your meta tags. While you could use functions, template params work better with SSR and avoid hydration issues.

Setup

First, add the plugin to your Unhead configuration:

Input
import { TemplateParamsPlugin } from '@unhead/plugins'
import { createHead } from 'unhead'

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

Built-in Params

Unhead includes two built-in template params:

TokenDescription
%sThe current page title
%separatorSmart separator (defaults to |)

The %separator is clever - it only appears between content and removes itself when:

  • The title is empty
  • Multiple separators would appear next to each other
Input
useHead({
  title: 'Home',
  titleTemplate: '%s %separator %siteName',
  templateParams: {
    separator: '', // Use an em dash instead of |
    siteName: 'MySite'
  }
})
Output
<title>Home — MySite</title>

Choosing a Separator

The default | separator isn't great for readability. Try these instead:

type Separator = '-' | '' | '' | '·' | '❤️'

Meta Tags and Social Sharing

Template params work great with SEO meta tags and social sharing:

Input
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!' }
  ]
})
Output
<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>

Enable for Other Tags

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

Input
useHead({
  templateParams: { name: 'My App' },
  script: [
    {
      innerHTML: { name: '%name' },
      type: 'application/json',
      processTemplateParams: true
    }
  ]
})
Output
<script type="application/json">{ "name": "My App" }</script>

Disable for Specific Tags

Add processTemplateParams: false to skip template processing:

Input
useHead({
  title: 'Hello %name',
  templateParams: { name: 'World' },
}, {
  processTemplateParams: false,
})
Output
<title>Hello %name</title>

Complex Example

Here's how you might use template params with nested objects and multiple tags:

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',
    },
  ],
})
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>
Did this page help you?