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 likepreact/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: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:(vnode: VNode) => void
Use cases:
- Inject additional props
- Track component creation
- Implement custom prop transformations
- Add metadata to vnodes
src/index.d.ts:329
Example - Auto-inject props:
diffed
Invoked after a vnode has been diffed and rendered:(vnode: VNode) => void
Use cases:
- Track render completion
- Measure render performance
- Update external state after render
- Implement custom side effects
src/index.d.ts:333
Example - Performance monitoring:
unmount
Invoked immediately before a vnode is unmounted:(vnode: VNode) => void
Use cases:
- Custom cleanup logic
- Track component lifecycle
- Remove external references
- Clear caches or subscriptions
src/index.d.ts:331
Example - Resource cleanup:
event
Transform or handle events before they’re dispatched:(event: Event) => any
Use cases:
- Event normalization
- Analytics tracking
- Custom event handling
- Polyfill event properties
src/index.d.ts:334
Example - Event analytics:
requestAnimationFrame
Customize how Preact schedules effects:(callback: () => void) => void
Use cases:
- Custom scheduling strategies
- Testing (synchronous effects)
- Server-side rendering
- Performance optimization
src/index.d.ts:335
Example - Synchronous effects for testing:
debounceRendering
Control when state updates trigger re-renders:(callback: () => void) => void
Use cases:
- Batch multiple state updates
- Control render timing
- Testing (synchronous renders)
- Performance optimization
src/index.d.ts:336
Example - Synchronous rendering for tests:
useDebugValue
Custom display for hook values in DevTools:(value: string | number) => void
Use cases:
- Custom DevTools integration
- Debugging custom hooks
- Development logging
src/index.d.ts:337
_addHookName
Add custom labels for hooks in DevTools:(name: string | number) => void
Source: src/index.d.ts:338, devtools/src/index.js:11-12
__suspenseDidResolve
Callback when Suspense boundary resolves:(vnode: VNode, callback: () => void) => void
Use cases:
- Track Suspense states
- Custom loading behavior
- Analytics
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:_root
Invoked before rendering begins:(vnode: VNode, parentNode: Element) => void
Example from preact/debug:
src/internal.d.ts:29, debug/src/debug.js:119-146
_diff
Invoked before a vnode is diffed:(vnode: VNode) => void
Example from preact/debug:
src/internal.d.ts:31, debug/src/debug.js:148-245
_render
Invoked before a component renders:(vnode: VNode) => void
Example - Infinite loop detection:
src/internal.d.ts:35, debug/src/debug.js:249-272
_commit
Invoked after DOM updates are committed:(vnode: VNode, commitQueue: Component[]) => void
Use cases:
- Track DOM mutations
- Trigger side effects after paint
- Integration with other libraries
src/internal.d.ts:33
_hook
Invoked when hooks are called:(component: Component, index: number, type: HookType) => void
Hook types:
HookType.useState = 1HookType.useReducer = 2HookType.useEffect = 3HookType.useLayoutEffect = 4HookType.useRef = 5HookType.useImperativeHandle = 6HookType.useMemo = 7HookType.useCallback = 8HookType.useContext = 9HookType.useErrorBoundary = 10HookType.useDebugValue = 11
src/internal.d.ts:3-16, src/internal.d.ts:37
Example - Hook validation:
debug/src/debug.js:59, debug/src/debug.js:274-280
_catchError
Called when an error is caught:(error: any, vnode: VNode, oldVNode?: VNode, errorInfo?: ErrorInfo) => void
Example from preact/debug:
src/internal.d.ts:41-46, debug/src/debug.js:78-117
_hydrationMismatch
Called when hydration finds mismatched nodes:(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:debug/src/debug.js:56-68
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
- Always chain hooks: Call previous hooks to support multiple libraries
- Minimize overhead: Keep hook logic lightweight
- Clean up: Remove hooks when done (restore previous values)
- TypeScript: Use proper types from
preact/src/internal.d.ts - Test thoroughly: Options hooks affect all components
- Document: Make it clear your library uses options hooks
- 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 diffdiffed: After every render_render: Before every component render