guides

Tag Sorting

How tags are sorted and how to configure them.

Once tags are deduped, they will be sorted. Sorting the tags is important to ensure critical tags are rendered first, as well as allowing you to have tags in a specific order that you need them in.

For example, if you need to preload an asset, you'll need this to come before the asset itself. Which is a bit of a challenge when the tags are nested.

Sorting Logic

Sorting is done in multiple steps:

  • order critical tags first
  • order by provided tagPriority
  • order by natural order they were registered

Critical Tags

The following critical tags have their own default tagPriority:

  • -2 - <meta charset ...>
  • -1 - <base>
  • 0 - <meta http-equiv="content-security-policy" ...>
  • 1 - <title>
  • 2 - <link rel="preconnect" ...>

All other tags have a default priority of 10: <meta>, <script>, <link>, <style>, etc

tagPriority

You can also set custom priorities for tags using the tagPriority attribute.

The following aliases exist:

  • tagPriority: 'critical' - 2
  • tagPriority: 'high' - 9
  • tagPriority: 'low' - 11

Otherwise, you can either provide a number or a string beginning with before: or after: and target a tag key.

Sort by number

When providing a number, refer to the priorities set for critical tags above.

// some layout we have a js file that is ran
useHead({
  script: [
    {
      src: '/not-important-script.js',
    },
  ],
})
// but in our page we want to run a script before the above
useHead({
  script: [
    {
      src: '/very-important-script.js',
      tagPriority: 0,
    },
  ],
})
// <script src=\"/very-important-script.js\"></script>
// <script src=\"/not-important-script.js\"></script>

Sort with before: and after:

When providing a string, you can use before: or after: to target a tag key.

Tag keys are prefixed with their tag name to avoid dedupe collisions, so you need to use the form of {tagName}:{key}.

useHead({
  script: [
    {
      key: 'not-important',
      src: '/not-important-script.js',
    },
  ],
})
useHead({
  script: [
    {
      // script is the tag name to target, `not-important` is the key we're targeting
      tagPriority: 'before:script:not-important',
      src: '/must-be-first-script.js',
    },
  ],
})
// <script src=\"/must-be-first-script.js\"></script>
// <script src=\"/not-important-script.js\"></script>

Hydration Caveats

When hydrating the state, either through mounting a SSR document or switching between pages, the package is dealt with a problem.

How to handle previously rendered tags that need to be replaced?

To do so Unhead will simply replace the tag in its current position. This provides a nicer UX with less tags jumping around.

This means that the tagPriority may not be honoured when hydrating.