Bottom sheet chrome — backdrop, grab handle, drag-to-dismiss, pinned footer. The base for CommentThread / Onboarding.
Anatomy
(backdrop: black/50 + blur) ┌ surface, rounded-t-12, max-w-430, max-h-85dvh ┐ │ ▭ grab handle (32×4, outline) │ ← drag region │ Title × │ ├────────────────────────────────────────────────┤ │ children (scrolls, min-h-0 flex-1) │ ├────────────────────────────────────────────────┤ │ footer (pinned, border-t, safe-area pad) │ └──────────────────────────────────────────────────┘
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
open | boolean | — | Controlled visibility. |
onOpenChange | (open: boolean) => void | — | Fired by backdrop tap, Escape, close button, and drag-dismiss. |
title | ReactNode | — | Header + accessible Dialog.Title. |
children | ReactNode | — | Scrolling body. |
footer | ReactNode | — | Optional pinned-bottom region. |
className | string | — | Extra classes on the panel. |
Motion
Slide-up on open, slide-down on close; drag follows 1:1 then settles. Reduced-motion: the global reset collapses the slide/settle.
A11y
- · Radix Dialog: focus trap,
Escape, scroll lock,role="dialog", labelled bytitle. - · Close button is 28px with an
aria-label; the handle is a redundant affordance, not the only dismiss. - · Centered
max-w-430so it reads as a phone-width sheet on desktop too.