Doc Page
Troubleshooting
Diagnose common contract, ARIA, and adapter mismatch issues quickly.
Start With The DOM
When a primitive misbehaves, inspect the rendered DOM before changing adapter code:
- Find the root or trigger with
data-ui. - Confirm every required
data-slotexists. - Confirm
data-statematches visible state. - Follow
aria-controls,aria-labelledby,aria-describedby, andaria-activedescendant. - Check
hidden,tabIndex, and disabled attributes.
Most bugs become clearer once the DOM contract is visible.
Save a minimal DOM snapshot before changing code. Checking root, slot, state, ARIA, focus, and hidden attributes against the docs is often faster than reading adapter source. Many issues are incomplete wrappers, partial example copies, or nondeterministic SSR state.
A short order of operations:
- Confirm the route and adapter are correct.
- Confirm the DOM contract is complete.
- Reproduce the keyboard path.
- Only then change controller or adapter code.
Sources: shared/en/troubleshooting
Broken ARIA Linkage
Symptoms:
- Screen reader does not announce title or selected option.
- Trigger says expanded but points to missing content.
- Combobox highlight is silent.
- Tabs panel is not associated with the active tab.
Fix:
- Make IDs deterministic.
- Render the target slot.
- Keep IDs stable across SSR/hydration.
- Do not conditionally remove the element that an ARIA attribute references unless you also update the reference.
Quick check:
document.getElementById(trigger.getAttribute("aria-controls"));If it returns null, fix IDs or render the target before changing styles. Tabs, Dialog, Popover, Select, Combobox, and Tooltip all rely on linkage for accessible context.
Sources: shared/en/troubleshooting
Keyboard Does Not Work
Symptoms:
- Arrow keys do nothing.
Escapedoes not close a layer.EnterorSpacedoes not commit selection.Tabescapes a modal dialog.
Fix:
- Confirm the focus target is the expected slot.
- Confirm event handlers are not overwritten by host wrappers.
- Confirm disabled items are registered as disabled, not removed from the model.
- Confirm roving focus has exactly one
tabIndex=0item.
For custom wrappers, inspect event handler composition. Host onKeyDown should not overwrite the adapter handler; it should compose with it and respect event.defaultPrevented. Missing a single keydown handler can make roving focus look randomly broken.
Sources: shared/en/troubleshooting
Controlled State Is Stuck
Symptoms:
- Click callback fires but UI does not change.
data-stateremains stale.- Selected option does not update.
Fix:
- In controlled mode, update the controlled prop in the callback.
- Do not pass both
valueanddefaultValuefor the same state. - In Vue/Solid/Svelte, avoid stale closure reads of reactive values.
- In Vanilla, call
sync()after host-controlled state changes when the binding requires it.
Reduce the case to one value, one callback, and two options. If the callback fires but DOM does not update, the issue is usually the external state owner. If DOM updates but callback does not fire, inspect adapter event mapping or disabled/readonly checks.
Sources: shared/en/troubleshooting
Layer Closes Unexpectedly
Symptoms:
- Popover closes when interacting with a Select inside it.
- Parent menu closes before submenu interaction completes.
- Dialog closes when opening a nested dialog.
Fix:
- Confirm portalled content keeps ARIA/control ownership.
- Confirm dismissable branches include related floating content where required.
- Confirm outside
pointerdownis evaluated against the active layer boundary. - Test nested layers with pointer, focus, and
Escape, not only click.
Portalled content is the usual trap. Moving content in the DOM does not remove semantic ownership. A Select content portalled to body can still belong to an active Popover boundary; otherwise selecting an option may be misread as an outside click.
Sources: shared/en/troubleshooting
SSR Or Hydration Drift
Symptoms:
- Server markup differs from client.
- ARIA IDs change after mount.
- Closed content flashes open.
- Focus trap activates before content is ready.
Fix:
- Provide explicit IDs for SSR-sensitive instances.
- Keep initial controlled state deterministic.
- Delay measurement until client mount.
- Keep closed floating content hidden before positioning.
If the bug only appears in production SSR, check:
- IDs generated from nondeterministic order.
- Server/client mismatch in
defaultOpen,defaultValue, or locale data. - Theme or media-query scripts that branch markup.
- Portal targets that exist only on the client without adapter guards.
Sources: shared/en/troubleshooting
Copied Example Fails In App
Symptoms:
- The site example works, but the copied app code does not.
- The UI looks similar, but keyboard or screen reader behavior differs.
- A Vanilla page keeps responding after unmount.
Fix:
- Copy the complete example structure again and verify labels, hidden inputs, collection data, and cleanup were not omitted.
- Ensure imports come from public adapter packages.
- Ensure app wrappers forward refs, IDs,
data-*, and adapter handlers. - Store the Vanilla binding return value and call destroy/cleanup on unmount.
- Check whether conditional rendering removed an element referenced by ARIA.
Sources: shared/en/troubleshooting
Search Or Docs Entry Looks Wrong
Symptoms:
- Search result points at the wrong adapter.
- A localized page falls back unexpectedly.
- Resources exposes maintainer-only release or rollback material.
Fix:
- Regenerate content for the current mode.
- Check that the docs slug has a shared base and any required adapter overlay.
- Keep user docs in the public catalog; maintainer playbooks should be reached through the dev-only internal docs switch.
- After production build, verify sitemap, search index, and bundle output do not contain internal-only routes.
Sources: shared/en/troubleshooting
Debug Commands
Repository checks:
pnpm content:check
pnpm test:contracts
pnpm --filter @nake-ui/docs test:unit
pnpm --filter @nake-ui/devtools-validator test:unitUse more focused adapter tests when the bug is framework-specific.
For content or generated artifacts, also run:
pnpm --filter @nake-ui/docs content:build
pnpm --filter @nake-ui/docs content:check
pnpm --filter @nake-ui/site test:unitSources: shared/en/troubleshooting
Checklist
- DOM contract inspected.
- ARIA references resolve.
- Keyboard focus target confirmed.
- Controlled owner updates state.
- Nested layer boundary tested.
- SSR IDs and initial state are deterministic.
- Copied examples preserve complete structure and cleanup.
- Production content does not expose dev-only internal doc entries.
Sources: shared/en/troubleshooting