---
title: "dom:rendered Hook · v2 · Unhead"
meta:
  "og:description": "Learn about the dom:rendered hook in Unhead that's called after all tags have been rendered to the DOM"
  "og:title": "dom:rendered Hook · v2 · Unhead"
  description: "Learn about the dom:rendered hook in Unhead that's called after all tags have been rendered to the DOM"
---

**Hooks**

# **dom:rendered Hook**

**On this page **

- [Hook Signature](#hook-signature)
- [Usage Example](#usage-example)
- [Use Cases](#use-cases)

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](#hook-signature)

```
export interface Hook {
  'dom:rendered': (ctx: { renders: DomRenderTagContext[] }) => HookResult
}
```

### [Parameters](#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](#returns)

`HookResult` which is either `void` or `Promise<void>`

## [Usage Example](#usage-example)

```
import { createHead } from '#imports'

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](#use-cases)

### [Performance Monitoring](#performance-monitoring)

Track and report rendering performance:

```
import { defineHeadPlugin } from '#imports'

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](#post-rendering-operations)

Perform operations that need to happen after all tags are rendered:

```
import { defineHeadPlugin } from '#imports'

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](#dom-cleanup)

Clean up old or unused elements after rendering:

```
import { defineHeadPlugin } from '#imports'

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

[Edit this page](https://github.com/unjs/unhead/edit/v2.1.2/docs/v2/head/7.api/hooks/11.dom-rendered.md)

**Did this page help you? **

[**dom:renderTag** Learn about the dom:renderTag hook in Unhead that controls how individual tags are rendered to the DOM](https://unhead.unjs.io/docs/v2/head/api/hooks/dom-render-tag) [**ssr:beforeRender** Learn about the ssr:beforeRender hook in Unhead that's called before server-side rendering of head tags](https://unhead.unjs.io/docs/v2/head/api/hooks/ssr-before-render)

**On this page **

- [Hook Signature](#hook-signature)
- [Usage Example](#usage-example)
- [Use Cases](#use-cases)