[Bug Fix] Dialog: match shadcn Base UI + vega
Related issue
Related to #570. Stacked on #580 and targets its branch; retarget to main once #580 merges.
Description
Brings Dialog in line with shadcn Base UI + vega, fixing what the shadcn-audit run on #580 flagged. A new audit run on this branch reports no failures on Dialog.
Look
- Panel:
bg-popover text-popover-foreground ring-1 ring-foreground/10 rounded-xl gap-6 text-sm, no shadow. In dark mode the text used to be black (the UACanvasText); it now uses the popover foreground. - Overlay:
::backdropisbg-black/10withbackdrop-blur-xs(wasbg-background/80). - Header uses
gap-2and is no longer centered on mobile. Title isfont-heading leading-none font-medium. Description styles links. - Close button is a 32px ghost icon button at
top-4 end-4with shadcn's hover, focus and press states.
Behavior and markup
- Title renders
<h2>(was<h3>). - The dialog gets
aria-labelledby/aria-describedbyfrom Title and Description, so it has the accessible name WAI-ARIA 1.2 requires. Attributes the author sets win. - The trigger's button gets
aria-haspopup="dialog",aria-expandedandaria-controls. - Open and close animate for 100ms on the panel and the backdrop. The controller waits for the exit animation before calling
close(). Withprefers-reduced-motionit closes at once. - New
show_close_button:onDialogContent(defaulttrue) andDialogFooter(defaultfalse, renders an outline Close button), matching shadcn'sshowCloseButton.
Changes existing apps will see
- Default width goes from 512px (
max-w-lg) to 448px (sm:max-w-md). Explicitsize:values are unchanged. - Title is smaller and lighter, and the header is left-aligned on mobile.
max-h-screenis gone; the native<dialog>already limits its height and scrolls.Buttonis now a generator dependency of Dialog.- Apps that copied the component need to regenerate the parts and the Stimulus controller together.
Audit files
audit/component_map.ymlmapsshowCloseButtontoshow_close_button.audit/divergences.ymlregisters the trigger wrapper<div>, since Phlex has no render prop.
| Before | After |
|---|---|
| (screenshot to add) | (screenshot to add) |
Testing instructions
cd gem && bundle exec rake(tests + standardrb).cd docs && bin/dev, then open/docs/dialog:- Open each example in light and dark mode and check the text is readable in dark mode.
- Esc, Cancel, the X and a backdrop click close the dialog with a short fade, and focus returns to the trigger.
- Pressing on the panel padding, or dragging from inside the panel onto the backdrop, keeps it open (the #580 fix).
- The "Close button" example has no X and shows a Close button in the footer.
- In a screen reader or the browser's accessibility tree, the dialog is announced as "dialog,
- With reduced motion on in the OS, the dialog opens and closes without animation.
š¤ Generated with Claude Code
Summary by cubic
Brings Dialog in line with shadcn's Base UI + vega styling and behavior, fixing the shadcn-audit findings from #580. The panel and overlay match the vega look, the title renders as an <h2>, the dialog gets its accessible name from Title/Description, the trigger exposes dialog ARIA state, and open/close now animate with a 100ms exit that waits for the animation before closing. The trigger's <div> wrapper and its motion-reduce tokens are registered as accepted divergences.
Changes
- Panel uses
bg-popover text-popover-foreground ring-1 ring-foreground/10 rounded-xl gap-6 text-sm; overlay isbg-black/10withbackdrop-blur-xs. - Header is left-aligned on mobile; title uses
font-heading leading-none font-medium; description styles links. - Close button is a 32px ghost icon button in the top-end corner with matching focus and press states.
- New
show_close_button:onDialogContent(defaulttrue) andDialogFooter(defaultfalse) to hide the corner X or add a footer Close button.Buttonis now a generator dependency of Dialog. - Controller sets
aria-labelledby/aria-describedbyand triggeraria-haspopup="dialog",aria-controls, andaria-expanded; author-set ids and ARIA are never overwritten, and the ARIA goes on the first interactive descendant of the trigger wrapper. - Closing (X, Cancel, Esc, backdrop) plays the exit animation before
close();prefers-reduced-motioncloses at once.
Breaking changes for existing apps
- Default width changes from 512px to 448px (
sm:max-w-md); explicitsize:values are unchanged. - Title is smaller and lighter; header is left-aligned on mobile.
max-h-screenis gone; the native<dialog>already limits height and scrolls.- Apps that copied the component need to regenerate the parts and the Stimulus controller together.