Hooks
tag:normalise Hook
On this page
The tag:normalise
hook is called for each individual tag during the normalization process. This hook gives you access to a single tag, its parent entry, and resolved options, allowing you to apply fine-grained modifications to specific tags.
Hook Signature
export interface Hook {
'tag:normalise': (ctx: {
tag: HeadTag
entry: HeadEntry<any>
resolvedOptions: CreateClientHeadOptions
}) => HookResult
}
Parameters
Name | Type | Description |
---|---|---|
ctx | Object | Context object containing the tag information |
ctx.tag | HeadTag | The head tag being normalized |
ctx.entry | HeadEntry<any> | The entry that generated this tag |
ctx.resolvedOptions | CreateClientHeadOptions | The resolved options for the head instance |
Returns
HookResult
which is either void
or Promise<void>
Usage Example
import { createHead } from '@unhead/svelte'
const head = createHead({
hooks: {
'tag:normalise': (ctx) => {
const { tag, entry } = ctx
// Apply specific modifications based on tag type
if (tag.tag === 'link' && tag.props.rel === 'stylesheet') {
// Add integrity check to all stylesheets
tag.props.crossorigin = 'anonymous'
}
// Add source information for debugging
tag._source = entry.options.source || 'unknown'
}
}
})
Use Cases
Fine-tuning Specific Tag Types
This hook is ideal for applying modifications to specific types of tags:
import { defineHeadPlugin } from '@unhead/svelte'
export const scriptSecurityPlugin = defineHeadPlugin({
hooks: {
'tag:normalise': (ctx) => {
const { tag } = ctx
// Add security attributes to all script tags
if (tag.tag === 'script' && tag.props.src) {
// Apply Content Security Policy attributes
tag.props.crossorigin = 'anonymous'
// Add nonce for CSP if available
if (globalThis.SCRIPT_NONCE) {
tag.props.nonce = globalThis.SCRIPT_NONCE
}
}
}
}
})
Tag Transformation Based on Environment
Transform tags differently based on the environment:
import { defineHeadPlugin } from '@unhead/svelte'
export const environmentSpecificPlugin = defineHeadPlugin({
hooks: {
'tag:normalise': (ctx) => {
const { tag, resolvedOptions } = ctx
const isDevelopment = process.env.NODE_ENV === 'development'
// Handle environment-specific transformations
if (tag.tag === 'meta' && tag.props.name === 'robots') {
// Prevent indexing in development or staging environments
if (isDevelopment || resolvedOptions.environment === 'staging') {
tag.props.content = 'noindex, nofollow'
}
}
// Add debug information in development
if (isDevelopment && tag.tag !== 'comment') {
tag.props['data-dev-info'] = `Entry: ${ctx.entry._i}`
}
}
}
})
Custom Attribute Processing
Process custom attributes that need special handling:
import { defineHeadPlugin } from '@unhead/svelte'
export const dataAttributeProcessingPlugin = defineHeadPlugin({
hooks: {
'tag:normalise': (ctx) => {
const { tag } = ctx
// Process data attributes with special formatting
Object.keys(tag.props).forEach((prop) => {
if (prop.startsWith('data-')) {
// Convert camelCase values to kebab-case for data attributes
if (typeof tag.props[prop] === 'string'
&& tag.props[prop].includes('_')) {
tag.props[prop] = tag.props[prop]
.replace(/_([a-z])/g, (_, char) => `-${char.toLowerCase()}`)
}
// Convert objects to JSON strings for data attributes
if (typeof tag.props[prop] === 'object' && tag.props[prop] !== null) {
tag.props[prop] = JSON.stringify(tag.props[prop])
}
}
})
}
}
})
Did this page help you?