feat(ui): native-HTML rewrite of stateful primitives + shadcn-API sweep#5
Merged
Conversation
Eight registry components now lean on native HTML primitives instead of
hand-rolled JS. Three drop their custom elements entirely; five keep a
thin custom-element wrapper around the platform feature.
Tier-2 -> Tier-1 (custom element removed; native HTML + class helpers):
- popover -> <button popovertarget=...> + <div popover> + CSS Anchor
Positioning. popoverContentClass({ side, align,
sideOffset, alignOffset }) emits literal Tailwind 4
arbitrary classes ([position-area:...], translate, etc).
Implicit anchor via popovertarget removes the inline
anchor-name / position-anchor styles for the common case.
- accordion -> <details name=...> + <summary>. The native name
attribute provides exclusive-open ("type=single").
accordionTriggerClass({ disabled }) renders the visual
disabled state; docs recommend native inert for full
keyboard prevention. orientation=horizontal is
deliberately not supported (fights <details>).
- collapsible -> <details> + <summary>. collapsibleTriggerClass({
disabled }) matches the accordion approach.
Tier-2 simplified internals (custom element stays, native does the work):
- dialog -> wraps <ui-dialog-content> in a programmatic <dialog>
and calls .showModal(). Native focus trap, Tab cycle,
Escape close, focus restore, and ::backdrop replace
~250 lines of hand-rolled JS. We retain body scroll
lock + auto-injected close X.
- alert-dialog -> same native <dialog> strategy; native Escape close
cancelled via the cancel event; no backdrop-click
dismissal (user must choose Cancel or Action).
- tooltip -> content opts into popover="manual" for top-layer +
z-index-free rendering. Added skip-delay-duration
attribute (module-level last-hide tracker, matches
shadcn TooltipProvider.skipDelayDuration). Added
align-offset attribute.
- hover-card -> content opts into popover="manual". Added
align-offset attribute.
- dropdown-menu -> content + sub-content opt into popover="manual".
Added align-offset attribute and typeahead behavior
(accumulated buffer cleared after 500ms inactivity,
text-value attribute overrides textContent). Existing
arrow-nav, submenu chain, outside-click, and Escape
are unchanged.
positionFloating(trigger, content, opts) — shared by all three tier-2
positioned components — extended to accept alignOffset.
Tier classification + docs:
- packages/ui/packages/website/app/_lib/tier.ts: TIER_2_NAMES shrinks
from 12 to 9.
- examples.ts: per-component code samples regenerated for the new APIs
(native popovertarget, native details/summary, dialog wrappers).
- component-api.ts: prop tables refreshed for every touched component;
the orientation=horizontal gap on accordion is documented inline.
- AGENTS.md + README.md: inventory and tier descriptions updated.
Also: AGENTS.md merge-workflow rule clarified — "merge to main" always
means gh pr create + gh pr merge via the GitHub CLI, never a local
git merge into main.
Tests:
- 128/128 ui package tests pass (5 new tests cover the new options on
popover, the disabled+inert recommendation on accordion/collapsible,
the align-offset wiring on tier-2 components, tooltip skip-delay, and
dropdown-menu typeahead).
- All 8 touched docs pages SSR with HTTP 200.
vivek7405
added a commit
that referenced
this pull request
May 21, 2026
…ep (#5) Eight registry components now lean on native HTML primitives instead of hand-rolled JS. Three drop their custom elements entirely; five keep a thin custom-element wrapper around the platform feature. Tier-2 -> Tier-1 (custom element removed; native HTML + class helpers): - popover -> <button popovertarget=...> + <div popover> + CSS Anchor Positioning. popoverContentClass({ side, align, sideOffset, alignOffset }) emits literal Tailwind 4 arbitrary classes ([position-area:...], translate, etc). Implicit anchor via popovertarget removes the inline anchor-name / position-anchor styles for the common case. - accordion -> <details name=...> + <summary>. The native name attribute provides exclusive-open ("type=single"). accordionTriggerClass({ disabled }) renders the visual disabled state; docs recommend native inert for full keyboard prevention. orientation=horizontal is deliberately not supported (fights <details>). - collapsible -> <details> + <summary>. collapsibleTriggerClass({ disabled }) matches the accordion approach. Tier-2 simplified internals (custom element stays, native does the work): - dialog -> wraps <ui-dialog-content> in a programmatic <dialog> and calls .showModal(). Native focus trap, Tab cycle, Escape close, focus restore, and ::backdrop replace ~250 lines of hand-rolled JS. We retain body scroll lock + auto-injected close X. - alert-dialog -> same native <dialog> strategy; native Escape close cancelled via the cancel event; no backdrop-click dismissal (user must choose Cancel or Action). - tooltip -> content opts into popover="manual" for top-layer + z-index-free rendering. Added skip-delay-duration attribute (module-level last-hide tracker, matches shadcn TooltipProvider.skipDelayDuration). Added align-offset attribute. - hover-card -> content opts into popover="manual". Added align-offset attribute. - dropdown-menu -> content + sub-content opt into popover="manual". Added align-offset attribute and typeahead behavior (accumulated buffer cleared after 500ms inactivity, text-value attribute overrides textContent). Existing arrow-nav, submenu chain, outside-click, and Escape are unchanged. positionFloating(trigger, content, opts) — shared by all three tier-2 positioned components — extended to accept alignOffset. Tier classification + docs: - packages/ui/packages/website/app/_lib/tier.ts: TIER_2_NAMES shrinks from 12 to 9. - examples.ts: per-component code samples regenerated for the new APIs (native popovertarget, native details/summary, dialog wrappers). - component-api.ts: prop tables refreshed for every touched component; the orientation=horizontal gap on accordion is documented inline. - AGENTS.md + README.md: inventory and tier descriptions updated. Also: AGENTS.md merge-workflow rule clarified — "merge to main" always means gh pr create + gh pr merge via the GitHub CLI, never a local git merge into main. Tests: - 128/128 ui package tests pass (5 new tests cover the new options on popover, the disabled+inert recommendation on accordion/collapsible, the align-offset wiring on tier-2 components, tooltip skip-delay, and dropdown-menu typeahead). - All 8 touched docs pages SSR with HTTP 200.
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
<dialog>.showModal()for dialog/alert-dialog;popoverattribute for tooltip/hover-card/dropdown-menu;<button popovertarget>+<div popover>+ CSS Anchor Positioning for popover;<details>/<summary>(+name=\"\") for accordion/collapsible.alignOffseteverywhere,skip-delay-durationon tooltip,text-valuetypeahead on dropdown-menu,disabledon accordion/collapsible triggers.accordion orientation=\"horizontal\"deliberately not supported (fights<details>);disabledships as visual-only with a JSDoc recommendation to combine with the nativeinertattribute.What changed in each component
dialog<dialog>and callsshowModal(). Native focus trap + Tab cycle + Escape +::backdropreplace ~250 lines of hand-rolled JS.alert-dialog<dialog>strategy; native Escape cancelled via thecancelevent; no backdrop-click dismissal.popoverpopoverattribute +popovertargetinvoker + CSS Anchor Positioning. Implicit anchor removes inline anchor-name / position-anchor for the common case.popoverContentClass({ side, align, sideOffset, alignOffset })accordion<details name=\"...\">+<summary>; native exclusive-open vianame.accordionTriggerClass({ disabled }). Documentsorientation=\"horizontal\"as not supported.collapsible<details>+<summary>.collapsibleTriggerClass({ disabled })tooltippopover=\"manual\"for top-layer + z-index-free rendering.skip-delay-duration,align-offsethover-cardpopover=\"manual\".align-offsetdropdown-menupopover=\"manual\".align-offset,text-value(typeahead)positionFloating(trigger, content, opts)(shared utility used by the tier-2 floating components) extended once to takealignOffset.Other updates
_lib/tier.ts—TIER_2_NAMESshrinks from 12 to 9.examples.ts,component-api.ts,docs/page.ts,page.ts— per-component code samples + prop tables refreshed.AGENTS.md,README.md— inventory + tier descriptions updated.AGENTS.mdmerge-workflow rule clarified: "merge to main" always meansgh pr create+gh pr merge, never a localgit mergeinto main.Test plan
npm test --workspace=@webjskit/ui— 128/128 pass (5 new tests cover new options on popover, thedisabled + inertrecommendation,align-offsetwiring across tier-2 components, tooltipskip-delay-duration, and dropdown-menu typeahead).[position-area:...], 36[margin-{dir}:Npx], 36translate-{x|y}-[±Npx]classes baked into source.