---
title: "dom:beforeRender Hook"
description: "Hook called before DOM rendering. Control render timing, prepare the DOM environment, and conditionally prevent head tag updates."
canonical_url: "https://unhead.unjs.io/docs/head/api/hooks/dom-before-render"
last_updated: "2026-06-30T06:51:30.481Z"
---

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) => SyncHookResult
}
```

### Parameters

<table>
<thead>
  <tr>
    <th>
      Name
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        ctx
      </code>
    </td>
    
    <td>
      <code>
        DomBeforeRenderCtx
      </code>
    </td>
    
    <td>
      Context object with rendering information
    </td>
  </tr>
</tbody>
</table>

The `DomBeforeRenderCtx` interface extends `ShouldRenderContext`:

```ts
interface DomBeforeRenderCtx extends ShouldRenderContext {
  tags: HeadTag[]
}

interface ShouldRenderContext {
  shouldRender: boolean
}
```

### Returns

`SyncHookResult` which is `void`. This hook is synchronous and cannot be async.

## 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 })
        }
      }
    }
  }
})
```
