guides

Tag Deduping

How duplicate tags are handled and how to extend them.

When implementing tags across an app hierachy, it's likely you'll want to override tags. This logic is called deduping.

Unhead determines which tags are duplicated based on whether you are allowed to have multiple of them in the DOM.

For example, you can only have one title, and a single <meta name="description">.

Deduping Logic

When you register multiple tags which are duplicated, only the most recent one will be used.

There is different logic used to determine what tags are duplicates:

  • Any of the following tags: base, title, titleTemplate, bodyAttrs, htmlAttrs.
  • <link rel="canonical">
  • <meta charset="">
  • Custom provided key attribute (hid and vmid is also supported)
  • Meta content, property and http-equiv attributes

Example of a dedupe using the meta content.

// called in a layout
useHead({
  meta: [
    {
      name: 'description',
      content: 'my site wide description',
    },
  ],
})
// called on a page
useHead({
  meta: [
    {
      name: 'description',
      content: 'my page description',
    },
  ],
})
// Only the last registered one is used
// <meta name="description" content="my page description" />

It's possible to base description to be rendered first using Tag Sorting.

Using arrays with <meta>

When you register multiple meta tags with the same name or property attributes, they will be deduped.

There are edge cases where this won't be useful though.

To prevent deduping in these instances, you can provide an array of values for the content attribute.

useHead({
  meta: [
    {
      name: 'google-site-verification',
      content: [
        'verification-id-1',
        'verification-id-2',
      ]
    },
  ],
})
// <meta name=\"google-site-verification\" content=\"verification-id-1\" >
// <meta name=\"google-site-verification\" content=\"verification-id-2\" >

Additionally, Unhead intuitive understands that duplicates within an entry should be safe.

useHead({
  meta: [
    {
      name: 'google-site-verification',
      content: 'verification-id-1'
    },
    {
      name: 'google-site-verification',
      content: 'verification-id-2'
    },
  ],
})
// <meta name=\"google-site-verification\" content=\"verification-id-1\" >
// <meta name=\"google-site-verification\" content=\"verification-id-2\" >

Providing a key

When you need more control over the deduping behaviour, you can provide a key to the tag.

The key is used as the duplicate key, ensuring that only one instance of the tag with that key exists.

This can be useful for ensuring only one instance of something is used across your site or removing nested tags

useHead({
  script: [
    {
      src: 'https://example.com/script.js',
      key: 'my-script',
    },
  ]
})

Note: this shares the same behaviour with hid and vmid from vue-meta.

tagDuplicateStrategy

The default behaviour when a duplicate is found, is to replace it.

The exception is when dealing with the attr keys htmlAttr and bodyAttr. The behaviour is to merge the data, allowing you to add additional attributes to the tag. This is especially useful for class and style props.

You can specify which strategy to use with the tagDuplicateStrategy.

// in a layout file we added a class
useHead({
  htmlAttrs: {
    class: 'my-class',
  },
})
// we don't want that class to be on a specific page, instead we want a new class
useHead({
  htmlAttrs: {
    tagDuplicateStrategy: 'replace',
    class: 'my-new-class',
  },
})
// <html class="my-new-class">

Examples

Removing a nested tag

// a layout file turns the bg red
useHead({
  style: [
    {
      key: 'red-bg',
      innerHTML: 'body { color: red }',
    }
  ]
})
// we want a specific page to remove the red bg
useHead({
  style: [
    {
      // a tag with only a key will be removed
      key: 'red-bg',
    }
  ]
})
// No style is rendered

Only one bg colour

// a layout file turns the bg red
useHead({
  style: [
    {
      key: 'bg-colour',
      innerHTML: 'body { color: red }',
    }
  ]
})
// we want to change it to blue in a seperate page
useHead({
  style: [
    {
      key: 'bg-colour',
      innerHTML: 'body { color: blue }',
    }
  ]
})