--- title: Tag Sorting & Placement description: How tags are positioned in the DOM and how to configure their order and location. --- **Quick Answer:** Use `tagPosition: 'head' | 'bodyOpen' | 'bodyClose'` to control where tags render. Use `tagPriority: 'critical' | 'high' | number | 'low'` to control ordering within those positions. ## Introduction By default, tags are rendered in the document ``{lang="html"} in a [specific order](#how-does-tag-sort-order-work) for optimal performance and compatibility. However, this is not always useful, say if you need to render a script at the end of the document or have a specific placement of a tag. To solve these issues we have three options: - [Document Placement](#how-do-i-control-where-tags-render-in-the-document): To control where the tag is rendered in the document (e.g. `head`{lang="bash"}, `bodyClose`{lang="bash"}, `bodyOpen`{lang="bash"}, etc) - [Sort Order](#how-does-tag-sort-order-work): To control the order of tags within the document section - [Hooks](#how-can-i-programmatically-reorder-tags): For advanced use cases, the `tags:afterResolve`{lang="bash"} hook allows programmatic reordering ## How do I control where tags render in the document? For the ` // ``` ## How does tag sort order work? All tags are given a weight with the lower the number, the higher the priority. [Capo.js](https://rviscomi.github.io/capo.js/) weights are automatically applied to tags to avoid [Critical Request Chains](https://web.dev/critical-request-chains/). As well as default weights to avoid site stability issues: - **-20**: ``{lang="html"} - **-10**: ``{lang="html"} - **0**: ``{lang="html"} - **10**: ``{lang="html"} - **20**: `<link rel="preconnect" ...>`{lang="html"} All other tags have a default priority of `100`{lang="bash"}. Escaping out of these default weights can be accomplished by setting the `tagPriority`{lang="bash"} property. ### How do I set tag priority? The `tagPriority`{lang="bash"} property can be set to an explicit weight, a string alias or a string to target a specific tag. #### Sorting with Aliases Using an alias to set the position of a tag is the best practice as it allows you to retain the existing capo.js weights that are configured for performance. - `critical`{lang="bash"}: **-8** - `high`{lang="bash"}: **-1** - `low`{lang="bash"}: **2** ```ts import { useHead } from '@unhead/dynamic-import' useHead({ script: [ { src: '/my-lazy-script.js', tagPriority: 'low', }, ], }) ``` #### Sort by number When providing a number, refer to the priorities set for critical tags above. ```ts import { useHead } from '@unhead/dynamic-import' // 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:` If you'd like to place a tag before or after another tag, you can use the optional [Alias Sorting Plugin](/docs/head/guides/plugins/alias-sorting) which provides a more intuitive way to order your tags relative to each other. ::tip The Alias Sorting Plugin is particularly useful when you need precise control over tag order but don't want to manage numerical priorities directly. :: ### Why is tagPriority ignored during hydration? When hydrating the state (e.g., SSR or page switch), Unhead replaces existing tags in their current position to avoid a flash of content. This may cause `tagPriority` to be ignored during hydration. For client-side-only applications or SPAs, this isn't an issue, but for SSR applications, be aware that the initial render positions may be preserved during hydration. ## How can I programmatically reorder tags? For advanced use cases where you need programmatic control over tag ordering, Unhead provides a powerful hook system. The `tags:afterResolve`{lang="bash"} hook gives you access to the tags after they've been resolved but before they're rendered to the DOM. This allows for custom ordering logic beyond what's possible with `tagPriority`{lang="bash"}. ```ts import { injectHead } from '@unhead/dynamic-import' const head = injectHead() // Hook into the tags:afterResolve lifecycle head.hooks.hook('tags:afterResolve', (ctx) => { // ctx.tags is an array of all tags that will be rendered // You can reorder, filter, or modify them before they are rendered // Example: Move all font preloads to the beginning const fontPreloads = ctx.tags.filter(tag => tag.tag === 'link' && tag.props.rel === 'preload' && tag.props.as === 'font' ) // Remove the font preloads from their current position ctx.tags = ctx.tags.filter(tag => !(tag.tag === 'link' && tag.props.rel === 'preload' && tag.props.as === 'font') ) // Add them to the beginning of the array ctx.tags = [...fontPreloads, ...ctx.tags] }) ``` ::tip The hooks approach is particularly useful for: - Complex ordering logic that depends on runtime conditions - Dynamic reordering based on user preferences or device capabilities - Implementation of custom sorting algorithms for specific tag types :: ## Key Takeaways ::tip - Use `tagPosition` to control where tags render (head, bodyOpen, bodyClose) - Use `tagPriority` for ordering: 'critical', 'high', number, 'low' - Critical tags like charset and viewport should have highest priority - Scripts can be moved to body end for better performance :: ## See Also - [Alias Sorting Plugin](/docs/head/guides/plugins/alias-sorting) - Sort tags by alias - [Handling Duplicates](/docs/head/guides/core-concepts/handling-duplicates) - Deduplication strategies - [useHead() API](/docs/head/api/composables/use-head) - tagPriority option