--- title: Handling DOM Events description: Learn how to use DOM event listeners with body attributes and non-script elements. navigation.title: DOM Event Handling --- ## Introduction Unhead provides support for native DOM event handling, allowing you to attach event listeners to document elements through head management. This feature enables you to execute code in response to various browser events like window resizing, navigation changes, or print events. ::note This guide focuses on non-script DOM events, particularly those attached to the body element. For script-specific event handling and loading, please refer to the [Loading Scripts](/guides/loading-scripts) guide which covers the more powerful `useScript()` composable. :: ## Resource Loading for Stylesheets For non-script resources like stylesheets, Unhead supports standard HTTP-related events. However, these are generally only needed in special cases. ```ts import { useHead } from '@unhead/dynamic-import' useHead({ link: [ { rel: 'stylesheet', href: '/assets/critical.css', onload: () => { console.log('Critical CSS loaded') // Load non-critical resources loadDeferredResources() }, onerror: () => { console.error('Failed to load stylesheet - using fallback styles') applyFallbackStyles() } } ] }, { mode: 'client' }) ``` ::note Remember that stylesheet events should also be used with `{ mode: 'client' }` to ensure they work correctly with SSR. :: ## Document and Window Events Unhead allows you to attach event handlers to the document body through the `bodyAttrs` property. These events effectively let you respond to document and window-level events. ::note Per the HTML specification, body event handlers are automatically proxied to the `window` object for better browser compatibility. :: ### Supported Body Events These events are only supported with `bodyAttrs` and provide access to various browser lifecycle events: ```ts import { useHead } from '@unhead/dynamic-import' // Types for body event handlers interface BodyEvents { // Printing events onafterprint?: string | ((el: Element) => void) // After print dialog closes onbeforeprint?: string | ((el: Element) => void) // Before print dialog opens // Page lifecycle events onbeforeunload?: string | ((el: Element) => void) // Before page is unloaded onload?: string | ((el: Element) => void) // Page finished loading onunload?: string | ((el: Element) => void) // Page is being unloaded // Navigation events onhashchange?: string | ((el: Element) => void) // URL hash has changed onpagehide?: string | ((el: Element) => void) // User navigates away onpageshow?: string | ((el: Element) => void) // User navigates to page onpopstate?: string | ((el: Element) => void) // Window history changes // Connection events onoffline?: string | ((el: Element) => void) // Browser goes offline ononline?: string | ((el: Element) => void) // Browser goes online // Other events onerror?: string | ((el: Element) => void) // Error occurs onmessage?: string | ((el: Element) => void) // Message is received onresize?: string | ((el: Element) => void) // Window is resized onstorage?: string | ((el: Element) => void) // Web Storage is updated } ``` ::warning Remember that these events should generally be used with `{ mode: 'client' }` to ensure they work properly with server-side rendering. :: ## Practical Examples ### Responding to Window Resize Track window size changes and update application state: ```ts import { useHead } from '@unhead/dynamic-import' useHead({ bodyAttrs: { onresize: (e) => { console.log('Window resized', e) // Update responsive state, recalculate layouts, etc. } } }, { mode: 'client' }) ``` ### Tracking Page Load Performance Measure and report page load performance metrics: ```ts import { useHead } from '@unhead/dynamic-import' useHead({ bodyAttrs: { onload: () => { // Report page load timing data if (window.performance) { const perfData = window.performance.timing const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart console.log(`Page loaded in ${pageLoadTime}ms`) // Send to analytics if (window.analytics) { window.analytics.track('Page Load Time', { milliseconds: pageLoadTime }) } } } } }, { mode: 'client' }) ``` ### Handling Offline Status Notify users when they lose internet connection: ```ts import { useHead } from '@unhead/dynamic-import' useHead({ bodyAttrs: { onoffline: () => { // Show offline notification showNotification('You are currently offline. Some features may be unavailable.') }, ononline: () => { // Show back online notification showNotification('You are back online!') // Resync data if needed syncData() } } }, { mode: 'client' }) ``` ## Best Practices for DOM Events 1. **Always use `{ mode: 'client' }`** when working with event handlers to ensure proper hydration ```ts useHead({ bodyAttrs: { onresize: () => handleResize() } }, { mode: 'client' }) // Critical for event handlers ``` 2. **Keep event handlers lightweight** to avoid performance issues ```ts // Good: Lightweight handler that delegates complex logic useHead({ bodyAttrs: { onresize: () => requestAnimationFrame(recalculateLayout) } }, { mode: 'client' }) ``` 3. **Use `useScript()` for script-related events** rather than direct script event handlers ```ts // Prefer this approach for scripts useScript({ src: 'https://example.com/analytics.js', onLoaded: api => api.initialize() }) ``` 4. **Clean up resources** in event handlers to prevent memory leaks ```ts useHead({ bodyAttrs: { onload: () => { const observer = new ResizeObserver(handleResize) observer.observe(document.body) // Store cleanup function for framework to use return () => observer.disconnect() } } }, { mode: 'client' }) ``` ## When to Use DOM Events vs useScript | Scenario | Recommended Approach | |----------|---------------------| | Script loading and interaction | [`useScript()`](/docs/head/api/composables/use-script) | | Window resize handling | DOM events with `bodyAttrs` | | Page lifecycle events | DOM events with `bodyAttrs` | | Print events | DOM events with `bodyAttrs` | | Stylesheet loading | DOM events with `link` tags | | Online/offline detection | DOM events with `bodyAttrs` |