Revert: useId collision hypothesis was incorrect#101
Draft
Conversation
✅ Deploy Preview for kinu-sh ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
Co-authored-by: developit <[email protected]>
…ollisions
The Nav's DropdownMenu and ThemeCustomizer Dialog now use explicit `id`
props ("nav-demos" and "theme-customizer") instead of relying on Preact's
useId() counter. This prevents ID collisions that occurred when:
1. SSR prerendering generates useId values with a counter offset
2. Client hydration generates different useId values (starting from 0)
3. Preact hydration preserves the SSR DOM attributes without updating them
4. On client-side navigation, new components get counter-based IDs that
collide with the stale SSR IDs still in the DOM
Co-authored-by: developit <[email protected]>
Co-authored-by: developit <[email protected]>
Copilot
AI
changed the title
[WIP] Fix ID collisions in Kinu components during client-side transitions
Fix useId collisions after client-side navigation between /docs/* pages
Mar 18, 2026
…mponents Preact's tree-position-based useId() can produce collisions when SSR and client render trees diverge (e.g. lazy-loaded routes, Suspense boundaries). Replace with a simple global counter + useRef approach in src/lib/use-id.ts that guarantees unique IDs regardless of tree structure. Reverts demo workaround (explicit id props) in favor of this library-level fix that protects all users. Co-authored-by: developit <[email protected]>
Author
You're right — patching the demo was the wrong approach entirely. Rewrote the fix at the library level in |
Copilot
AI
changed the title
Fix useId collisions after client-side navigation between /docs/* pages
Fix useId collisions in components
Mar 18, 2026
Preact's tree-position-based useId() generates deterministic IDs based on where components sit in the virtual DOM tree. The Nav's DropdownMenu and Dialog always get the same IDs (P0-2, P0-3) regardless of which docs page is rendered. Content examples always get P0-4+. There are no collisions between persistent and dynamic components. The previous approaches were wrong: 1. Adding explicit IDs to demo components - unnecessary 2. Replacing Preact's useId with a global counter - would break SSR/hydration matching since a counter can't be deterministic across SSR and client renders Co-authored-by: developit <[email protected]>
Copilot
AI
changed the title
Fix useId collisions in components
Revert: useId collision hypothesis was incorrect
Mar 18, 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.
The original PR hypothesized that Preact's
useId()produces collisions between persistent Nav components and dynamically mounted docs content after client-side navigation. This was wrong.Preact's
useId()is tree-position-based, not counter-based. Components at the same tree position always produce the same deterministic IDs regardless of which/docs/*page is rendered:No collision exists. Both previous "fixes" were wrong:
idprops on demo components — unnecessaryuseIdreplacing Preact's built-in — actively harmful; a global counter cannot produce deterministic IDs across SSR/hydration boundariesThis PR reverts all changes back to the original state.
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.