--- title: "dom:beforeRender Hook" description: "Learn about the dom:beforeRender hook in Unhead that runs before tags are rendered to the DOM" navigation: title: "dom:beforeRender" --- The `dom:beforeRender` hook is called before tags are rendered to the DOM in client-side environments. This hook allows you to control whether rendering should proceed and provides access to rendering context. ## Hook Signature ```ts export interface Hook { 'dom:beforeRender': (ctx: DomBeforeRenderCtx) => HookResult } ``` ### Parameters | Name | Type | Description | |------|------|-------------| | `ctx` | `DomBeforeRenderCtx` | Context object with rendering information | The `DomBeforeRenderCtx` interface extends `ShouldRenderContext`: ```ts interface DomBeforeRenderCtx extends ShouldRenderContext { tags: DomRenderTagContext[] // Note: this is deprecated and will always be empty } interface ShouldRenderContext { shouldRender: boolean } ``` ### Returns `HookResult` which is either `void` or `Promise<void>` ## Usage Example ```ts import { createHead } from '@unhead/dynamic-import' const head = createHead({ hooks: { 'dom:beforeRender': (ctx) => { // Log rendering intent console.log('About to render tags to DOM') // You can prevent rendering by setting shouldRender to false if (window.document.querySelector('meta[name="unhead-rendered"]')) { console.log('Preventing re-render as tags are already rendered') ctx.shouldRender = false } } } }) ``` ## Use Cases ### Conditional Rendering Control whether rendering should proceed based on page conditions: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' export const conditionalRenderPlugin = defineHeadPlugin({ hooks: { 'dom:beforeRender': (ctx) => { // Only render head tags if we're not in a specific context if (window.location.pathname.startsWith('/admin')) { // For admin pages, we want to prevent automatic rendering // because we'll handle it differently ctx.shouldRender = false } // Prevent rendering during specific user interactions if (document.body.classList.contains('modal-open')) { // Don't update head while modal is open to prevent flickering ctx.shouldRender = false } } } }) ``` ### Render Preparation Prepare the DOM environment before rendering: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' export const renderPreparationPlugin = defineHeadPlugin({ hooks: { 'dom:beforeRender': () => { // Add rendering flag to prevent duplicate processing if (!document.querySelector('meta[name="unhead-render-id"]')) { const meta = document.createElement('meta') meta.setAttribute('name', 'unhead-render-id') meta.setAttribute('content', Date.now().toString()) document.head.appendChild(meta) } // Clean up specific tags that we always want to manage ourselves const existingCanonical = document.querySelector('link[rel="canonical"]') if (existingCanonical) { existingCanonical.remove() } } } }) ``` ### Delayed Rendering Set up delayed rendering for better performance: ```ts import { defineHeadPlugin } from '@unhead/dynamic-import' export const delayedRenderPlugin = defineHeadPlugin({ hooks: { 'dom:beforeRender': (ctx) => { // Check if this is the initial page load const isInitialLoad = !document.querySelector('[data-unhead-rendered]') if (isInitialLoad) { // For initial load, we can delay non-critical head updates // until the page has finished loading if (document.readyState !== 'complete') { // Delay rendering until page is complete ctx.shouldRender = false // Set up listener to trigger rendering when ready window.addEventListener('load', () => { // Force head to re-evaluate rendering setTimeout(() => { head.hooks.callHook('entries:updated', head) }, 0) }, { once: true }) } } } } }) ```