Hooks
dom:rendered Hook
On this page
The dom:rendered
hook is called after all tags have been rendered to the DOM. This hook provides access to the rendered elements and is useful for post-rendering operations, measurements, or triggering side effects that depend on the DOM being updated.
Hook Signature
export interface Hook {
'dom:rendered': (ctx: { renders: DomRenderTagContext[] }) => HookResult
}
Parameters
Name | Type | Description |
---|---|---|
ctx | Object | Context object containing rendering information |
ctx.renders | DomRenderTagContext[] | Array of rendered tag contexts |
The DomRenderTagContext
interface is defined as:
interface DomRenderTagContext {
id: string
$el: Element
shouldRender: boolean
tag: HeadTag
entry?: HeadEntry<any>
markSideEffect: (key: string, fn: () => void) => void
}
Returns
HookResult
which is either void
or Promise<void>
Usage Example
import { createHead } from '@unhead/svelte'
const head = createHead({
hooks: {
'dom:rendered': (ctx) => {
// Log total number of elements rendered
console.log(`Finished rendering ${ctx.renders.length} tags to the DOM`)
// Add a class to the document to indicate rendering is complete
document.documentElement.classList.add('head-rendered')
// Dispatch an event that other code can listen for
window.dispatchEvent(new CustomEvent('head-rendered', {
detail: { count: ctx.renders.length }
}))
}
}
})
Use Cases
Performance Monitoring
Track and report rendering performance:
import { defineHeadPlugin } from '@unhead/svelte'
export const performanceMonitorPlugin = defineHeadPlugin({
hooks: {
'dom:rendered': (ctx) => {
// Calculate rendering metrics
const renderCount = ctx.renders.length
// Record performance entry
if (window.performance && window.performance.mark) {
window.performance.mark('unhead-dom-rendered')
// Calculate time since navigation start
const navStart = window.performance.timing.navigationStart
const renderTime = Date.now() - navStart
// Log performance data
console.log(`Head rendering complete: ${renderCount} tags in ${renderTime}ms`)
// Create a performance measure
window.performance.measure('unhead-render-time', 'navigationStart', 'unhead-dom-rendered')
}
// Report to analytics if available
if (window.dataLayer) {
window.dataLayer.push({
event: 'unhead_rendered',
unhead_render_count: renderCount
})
}
}
}
})
Post-rendering Operations
Perform operations that need to happen after all tags are rendered:
import { defineHeadPlugin } from '@unhead/svelte'
export const postRenderPlugin = defineHeadPlugin({
hooks: {
'dom:rendered': (ctx) => {
// Find all script tags that were rendered
const scriptElements = ctx.renders
.filter(render => render.tag.tag === 'script')
.map(render => render.$el)
// Set up monitoring for script completion
if (scriptElements.length > 0) {
let loadedCount = 0
// Track when all scripts have loaded
const scriptLoadHandler = () => {
loadedCount++
if (loadedCount === scriptElements.length) {
console.log('All head scripts have loaded')
document.body.classList.add('scripts-ready')
// Notify application that scripts are ready
window.dispatchEvent(new CustomEvent('head-scripts-loaded'))
}
}
// Monitor each script
scriptElements.forEach((script) => {
if (script.hasAttribute('async') || script.hasAttribute('defer')) {
script.addEventListener('load', scriptLoadHandler, { once: true })
script.addEventListener('error', scriptLoadHandler, { once: true })
}
else {
// Synchronous scripts are already loaded at this point
loadedCount++
}
})
// If all scripts were synchronous, trigger the event now
if (loadedCount === scriptElements.length) {
scriptLoadHandler()
}
}
}
}
})
DOM Cleanup
Clean up old or unused elements after rendering:
import { defineHeadPlugin } from '@unhead/svelte'
export const domCleanupPlugin = defineHeadPlugin({
hooks: {
'dom:rendered': (ctx) => {
// Get IDs of all rendered elements
const renderedIds = new Set(ctx.renders.map(render => render.id))
// Find elements with data-unhead-id that weren't in this render batch
const outdatedElements = document.querySelectorAll('[data-unhead-id]')
Array.from(outdatedElements).forEach((element) => {
const id = element.getAttribute('data-unhead-id')
if (id && !renderedIds.has(id)) {
// This element was from a previous render and is no longer needed
console.log('Removing outdated head element:', element)
element.parentNode?.removeChild(element)
}
})
// Clean up any temporary markers
document.querySelectorAll('[data-unhead-temp]').forEach((el) => {
el.parentNode?.removeChild(el)
})
}
}
})
Did this page help you?