---
title: "Handling DOM Events · Unhead"
canonical_url: "https://unhead.unjs.io/docs/svelte/head/guides/core-concepts/dom-event-handling"
last_updated: "2026-08-01T10:26:42.257Z"
meta:
  description: "Attach client-side load, error, and body event handlers through useHead, with SSR hydration support."
  "og:description": "Attach client-side load, error, and body event handlers through useHead, with SSR hydration support."
  "og:title": "Handling DOM Events · Unhead"
---

Home

`
Unhead on GitHub

Switch to SvelteSwitch to TypeScriptSwitch to VueSwitch to ReactSwitch to Solid.jsSwitch to AngularSwitch to Nuxt

**Core Concepts**

# **Handling DOM Events**

[Copy for LLMs](https://raw.githubusercontent.com/unjs/unhead/refs/heads/main/docs/head/1.guides/1.core-concepts/8.dom-event-handling.md)

Pass functions to supported `**on***` properties. Scripts support `**onload**` and `**onerror**`; stylesheet, preload, and module-preload links support load and error events; `**bodyAttrs**` supports window-level body events.

## Rendering and hydration

On the client, Unhead installs listeners with `**addEventListener()**` and removes or replaces them when the owning entry changes. Functions are not serialized into HTML.

During SSR, a function handler is rendered as a small marker handler such as:

```
<script onload="this.dataset.onloadfired = true"></script>
```

If the event fires before hydration, the marker lets the client renderer replay the handler with a synthetic event after adopting the element. You should therefore register the same handler during SSR and hydration. Wrapping `**useHead()**` in `**if (import.meta.client)**` removes this replay path and can also produce different server and client head entries.

## Resource events

```
import { useHead } from '@unhead/svelte'

useHead({
  link: [
    {
      rel: 'stylesheet',
      href: '/assets/critical.css',
      onload: event => console.log('Stylesheet loaded', event),
      onerror: event => console.error('Stylesheet failed', event)
    }
  ],
  script: [
    {
      src: '/assets/app.js',
      defer: true,
      onload: event => console.log('Script loaded', event),
      onerror: event => console.error('Script failed', event)
    }
  ]
})
```

Browsers fire `**load**` after a stylesheet and its imports have loaded and parsed, and `**error**` if stylesheet processing fails. Script elements likewise receive `**load**` or `**error**` after the external resource is accepted or rejected. See the MDN references for [`**<link>**`**~~ load events~~**](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/link#stylesheet_load_events) and [`**<script>**`**~~ loading~~**](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script#notes).

Use [`**useScript()**`](https://unhead.unjs.io/docs/head/api/composables/use-script) when you need triggers, a load promise, API resolution, warmup hints, or reusable `**onLoaded()**` and `**onError()**` callbacks.

## Body events

Handlers under `**bodyAttrs**` are attached to `**window**`, with `**this**` bound to `**document.body**`. Each handler receives its native `**Event**` object.

```
import { useHead } from '@unhead/svelte'

useHead({
  bodyAttrs: {
    onresize(event) {
      console.log('Window resized', event)
    },
    onoffline() {
      showNotification('You are offline.')
    },
    ononline() {
      showNotification('You are back online.')
    }
  }
})
```

Supported body event names include `**onafterprint**`, `**onbeforeprint**`, `**onbeforeunload**`, `**onerror**`, `**onhashchange**`, `**onload**`, `**onmessage**`, `**onoffline**`, `**ononline**`, `**onpagehide**`, `**onpageshow**`, `**onpopstate**`, `**onresize**`, `**onstorage**`, and `**onunload**`.

## Cleanup

Unhead removes a listener when its entry is patched without that handler or when the entry is disposed. The return value of an event handler is ignored; returning a cleanup function from `**onload**` does not register cleanup work.

If a handler creates its own observer, timer, or subscription, clean that resource up through your framework's component lifecycle.

## See Also

- [**~~Loading Scripts~~**](https://unhead.unjs.io/docs/head/guides/core-concepts/loading-scripts): Managed script loading
- [**~~useScript() API~~**](https://unhead.unjs.io/docs/head/api/composables/use-script): Script callbacks and triggers
- [**~~useHead() API~~**](https://unhead.unjs.io/docs/head/api/composables/use-head): Head entry reference

[~~Edit this page~~](https://github.com/unjs/unhead/edit/main/docs/head/1.guides/1.core-concepts/8.dom-event-handling.md)

[~~Markdown For LLMs~~](https://raw.githubusercontent.com/unjs/unhead/refs/heads/main/docs/head/1.guides/1.core-concepts/8.dom-event-handling.md)

**Did this page help you? **

[**Tag Deduplication** Automatic tag deduplication by key, name, and property. Override layout tags in pages, manage verification tags, and customize merge strategies.](https://unhead.unjs.io/docs/head/guides/core-concepts/handling-duplicates) [**Script Loading** Load external scripts with useScript(), shared instances, triggers, API resolution, callbacks, and resource warmup.](https://unhead.unjs.io/docs/head/guides/core-concepts/loading-scripts)

**On this page **

- [Rendering and hydration](#rendering-and-hydration)
- [Resource events](#resource-events)
- [Body events](#body-events)
- [Cleanup](#cleanup)
- [See Also](#see-also)