feat: access resolved head with onRendered#712
Merged
Conversation
Adds a client-side callback option to useHead/useSeoMeta/useHeadSafe that fires after DOM updates are applied. This enables synchronizing external tools (e.g. analytics) with the current document head state. The callback is automatically cleaned up when the entry is disposed (including on component unmount). Ignored during SSR. Resolves #615 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
📝 WalkthroughWalkthroughAdds a client-only Changes
Sequence Diagram(s)sequenceDiagram
participant App as Client App
participant CH as createHead (client)
participant Core as unhead Core
participant DOM as DOM renderer
App->>CH: push(input, { onRendered })
CH->>Core: core.push(input, optionsWithoutCallbacks)
CH-->>CH: register dom:rendered hook (store unhook)
Core->>DOM: apply DOM updates
DOM->>CH: dom:rendered event with renders[]
CH->>App: invoke onRendered({ renders })
App->>CH: entry.dispose()
CH->>CH: call unhook() (cleanup)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Contributor
Bundle Size Analysis
|
The client createHead wraps core push() with its own push(), and hooks are only available on the client wrapper. Moved hook registration to the client head's push() where hooks are accessible. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The onRendered hook was registered after entries:updated was called, but entries:updated synchronously triggers the renderer which fires dom:rendered. This meant the callback was never invoked on the initial render. Also fixes multi-entry test expectations to account for each push() triggering an immediate render, and adds a Vue component unmount test to verify onRendered cleanup on component lifecycle. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Wrap onRendered callbacks to run within the registering component's scope context. This ensures reactive tracking works correctly and provides an extra safety layer — disposed scopes silently no-op. - Vue: capture getCurrentScope(), run callback via scope.run() - Solid: capture getOwner(), run callback via runWithOwner() - React/Svelte/Angular: no scope concept — closures + disposal cleanup already handle this correctly Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
onRendered
3 tasks
Closed
This was referenced Apr 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
onRenderedcallback option toHeadEntryOptions, enabling users to synchronize external tools (e.g. analytics) with DOM head updatesuseHead()/useSeoMeta()/useHeadSafe()optionsonHeadUpdated()composable, extends existing options to avoid growing the API surfaceResolves #615
Supersedes #685
Changes
packages/unhead/src/types/head.ts— AddedonRenderedtoHeadEntryOptionspackages/unhead/src/unhead.ts— Hook registration inpush(), cleanup indispose()packages/unhead/test/unit/client/onRendered.test.ts— 7 core testspackages/vue/test/unit/dom/onRendered.test.ts— 5 Vue integration testsdocs/head/7.api/composables/0.use-head.md— API docs and usage guideonRenderedTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Tests