Skip to main content

Options API

The Options API is Preact’s extension mechanism that allows you to hook into the rendering lifecycle and customize its behavior. This is the foundation for addons like preact/debug, preact/compat, and preact/hooks.
The Options API is primarily for library authors and advanced use cases. Most application developers won’t need to use it directly.

Overview

The options object contains callback functions that Preact invokes at various stages of the rendering process:
Source: src/options.js:1-17

Public Options Hooks

These hooks are part of Preact’s public API and safe to use:

vnode

Invoked whenever a VNode is created, before it’s processed:
Type: (vnode: VNode) => void Use cases:
  • Inject additional props
  • Track component creation
  • Implement custom prop transformations
  • Add metadata to vnodes
Source: src/index.d.ts:329 Example - Auto-inject props:

diffed

Invoked after a vnode has been diffed and rendered:
Type: (vnode: VNode) => void Use cases:
  • Track render completion
  • Measure render performance
  • Update external state after render
  • Implement custom side effects
Source: src/index.d.ts:333 Example - Performance monitoring:

unmount

Invoked immediately before a vnode is unmounted:
Type: (vnode: VNode) => void Use cases:
  • Custom cleanup logic
  • Track component lifecycle
  • Remove external references
  • Clear caches or subscriptions
Source: src/index.d.ts:331 Example - Resource cleanup:

event

Transform or handle events before they’re dispatched:
Type: (event: Event) => any Use cases:
  • Event normalization
  • Analytics tracking
  • Custom event handling
  • Polyfill event properties
Source: src/index.d.ts:334 Example - Event analytics:

requestAnimationFrame

Customize how Preact schedules effects:
Type: (callback: () => void) => void Use cases:
  • Custom scheduling strategies
  • Testing (synchronous effects)
  • Server-side rendering
  • Performance optimization
Source: src/index.d.ts:335 Example - Synchronous effects for testing:

debounceRendering

Control when state updates trigger re-renders:
Type: (callback: () => void) => void Use cases:
  • Batch multiple state updates
  • Control render timing
  • Testing (synchronous renders)
  • Performance optimization
Source: src/index.d.ts:336 Example - Synchronous rendering for tests:

useDebugValue

Custom display for hook values in DevTools:
Type: (value: string | number) => void Use cases:
  • Custom DevTools integration
  • Debugging custom hooks
  • Development logging
Source: src/index.d.ts:337

_addHookName

Add custom labels for hooks in DevTools:
Type: (name: string | number) => void Source: src/index.d.ts:338, devtools/src/index.js:11-12

__suspenseDidResolve

Callback when Suspense boundary resolves:
Type: (vnode: VNode, callback: () => void) => void Use cases:
  • Track Suspense states
  • Custom loading behavior
  • Analytics
Source: src/index.d.ts:339

Internal Options Hooks

These hooks are used internally and by official addons. They’re not officially public but are stable:
Internal hooks may change between minor versions. Use with caution and test thoroughly when upgrading Preact.

_root

Invoked before rendering begins:
Type: (vnode: VNode, parentNode: Element) => void Example from preact/debug:
Source: src/internal.d.ts:29, debug/src/debug.js:119-146

_diff

Invoked before a vnode is diffed:
Type: (vnode: VNode) => void Example from preact/debug:
Source: src/internal.d.ts:31, debug/src/debug.js:148-245

_render

Invoked before a component renders:
Type: (vnode: VNode) => void Example - Infinite loop detection:
Source: src/internal.d.ts:35, debug/src/debug.js:249-272

_commit

Invoked after DOM updates are committed:
Type: (vnode: VNode, commitQueue: Component[]) => void Use cases:
  • Track DOM mutations
  • Trigger side effects after paint
  • Integration with other libraries
Source: src/internal.d.ts:33

_hook

Invoked when hooks are called:
Type: (component: Component, index: number, type: HookType) => void Hook types:
  • HookType.useState = 1
  • HookType.useReducer = 2
  • HookType.useEffect = 3
  • HookType.useLayoutEffect = 4
  • HookType.useRef = 5
  • HookType.useImperativeHandle = 6
  • HookType.useMemo = 7
  • HookType.useCallback = 8
  • HookType.useContext = 9
  • HookType.useErrorBoundary = 10
  • HookType.useDebugValue = 11
Source: src/internal.d.ts:3-16, src/internal.d.ts:37 Example - Hook validation:
Source: debug/src/debug.js:59, debug/src/debug.js:274-280

_catchError

Called when an error is caught:
Type: (error: any, vnode: VNode, oldVNode?: VNode, errorInfo?: ErrorInfo) => void Example from preact/debug:
Source: src/internal.d.ts:41-46, debug/src/debug.js:78-117

_hydrationMismatch

Called when hydration finds mismatched nodes:
Type: (vnode: VNode, excessDomChildren: Element[]) => void Source: src/internal.d.ts:48-51, debug/src/debug.js:582-590

Chaining Options

When multiple libraries use the options API, they should chain previous hooks:
Example from preact/debug:
Source: debug/src/debug.js:56-68
Always chain previous hooks to avoid breaking other libraries that use the options API.

Complete Example: Custom Devtools

Here’s a complete example building a simple custom devtools:

Use Cases

The Options API enables:
  • Debug tools: Validation and error reporting (preact/debug)
  • DevTools integration: Component inspection (preact/devtools)
  • React compatibility: React API emulation (preact/compat)
  • Performance monitoring: Render tracking and profiling
  • Analytics: User interaction tracking
  • Testing utilities: Synchronous rendering (preact/test-utils)
  • Custom renderers: Alternative render targets
  • State management: External state integration

Best Practices

  1. Always chain hooks: Call previous hooks to support multiple libraries
  2. Minimize overhead: Keep hook logic lightweight
  3. Clean up: Remove hooks when done (restore previous values)
  4. TypeScript: Use proper types from preact/src/internal.d.ts
  5. Test thoroughly: Options hooks affect all components
  6. Document: Make it clear your library uses options hooks
  7. Dev only: Consider only enabling in development mode

TypeScript Support

Extend the Options interface for custom hooks:

Performance Considerations

Options hooks are called frequently:
  • vnode: Every element/component creation
  • _diff: Before every diff
  • diffed: After every render
  • _render: Before every component render
Keep logic minimal to avoid performance impact: