---
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**: ``{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,
},
],
})
//
//
```
#### 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