Search for a command to run...
Adaptive modal — a centered card on desktop, a drag-handle bottom sheet on mobile. Built on Silk-HQ. For content and utility overlays (share, stats, guides, recorders). A form in an overlay is `FormDialog`.
DetachedSheet.Content automatically renders the dismiss affordance — a drag handle on mobile, an X close button on desktop (top-right). Pass showCloseButton={false} to suppress when the consumer wires its own dismiss. Width is handled by the primitive: the desktop card has a sensible minimum (md, 28rem) and grows to fit wider content; raise the floor with the size prop (sm/md/lg/xl). Mobile is always full-bleed. No inner fixed-width wrapper is needed.
DetachedSheet.RootState container. Wraps Silk-HQ's Sheet.Root and provides the Silk license + a dismiss handler over context (so CloseButton works without prop-drilling).
| Prop | Type | Default | Description |
|---|---|---|---|
presented | boolean | — | Controlled open state. |
onPresentedChange | (open: boolean) => void | — | Fires when the sheet opens or closes. |
When uncontrolled, manage state externally and pair with DetachedSheet.Trigger (asChild) for the open affordance.
DetachedSheet.ContentThe floating panel. Adaptive: centered card on min-width: 650px, bottom sheet below it. Forwards every Silk Sheet.Content prop.
| Prop | Type | Default | Description |
|---|---|---|---|
showCloseButton | boolean | true | Auto-renders the dismiss affordance — drag handle on mobile, X close button on desktop. Set false to render your own affordance. |
size | "sm" | "md" | "lg" | "xl" | "md" | Desktop min-width floor for the centered card (20 / 28 / 32 / 40rem). The card grows past it to fit wider content and is capped at the viewport. No effect on mobile (always full-bleed). |
On desktop the panel is w-fit with a size-driven min-width floor and a max-width: calc(100vw - 2rem) ceiling, so it is never narrower than the floor, never wider than the viewport, and grows to fit content in between. On mobile it is w-full. The default md (28rem) suits single-field forms; bump to lg/xl for multi-column content, lists, or recorders. You no longer need an inner fixed-width wrapper.
DetachedSheet.HeaderLayout slot. flex flex-col gap-1.5 p-6. Wraps Title + Description.
DetachedSheet.Title · DetachedSheet.DescriptionTypography slots. Title is required for screen-reader announcement (wrap in sr-only if you don't want it visible).
Title — text-xl font-medium tracking-tight text-fg-high. Left-aligned unless the header sits below a graphic. Visual-hero sheets may hide it with sr-only; a title is still required.Description — text-sm text-fg-mid.DetachedSheet.FooterLayout slot for action rows. flex flex-row gap-2 px-6 pt-4 pb-6.
DetachedSheet.CancelButton · DetachedSheet.SubmitButtonPre-tuned action buttons for the footer. CancelButton is variant="subtle" (paired 50/50), SubmitButton is variant="brand". Both ship size="xl" and flex-1 so paired actions split 50/50 and a lone primary is full-width. A lone dismiss (no primary) passes variant="ghost".
DetachedSheet.CloseButtonTop-right X button. Auto-included by Content on desktop — reach for it directly only when rendering a custom layout that opts out of the built-in affordance (showCloseButton={false}) but still wants the standard X.
DetachedSheet.HandleMobile-only drag handle. Auto-included by Content on mobile. Renders null on desktop. Use directly the same way as CloseButton if you've opted out of the built-in affordance.
DetachedSheet.Trigger · DetachedSheet.Outlet · DetachedSheet.Backdrop · DetachedSheet.View · DetachedSheet.PortalPass-throughs / structural wrappers around Silk's primitives. Trigger accepts asChild like Radix triggers.
Use DetachedSheet for content and utility overlays — share, stats, guides, recorders,
routers. A form in an overlay is FormDialog.
Let the primitive own width. The default md card is usable out of the box; reach for the
size prop (lg/xl) when the content needs a wider floor. Don't put width utilities on
DetachedSheet.Content — it's w-fit, so a max-w-*/w-* className there won't widen the
visible card.
Use DetachedSheet.CancelButton + DetachedSheet.SubmitButton inside DetachedSheet.Footer
for action rows. Subtle cancel + brand primary, size="xl", 50/50 when paired.
Leave showCloseButton on its default true. The primitive picks the right affordance per
viewport — drag handle on mobile, X on desktop.
Wire your own close button when showCloseButton is on. You'll double up the dismiss affordance
on desktop and have an extra element to maintain.
Put a form in a raw DetachedSheet. FormDialog owns that contract on every viewport.
Skip DetachedSheet.Title because the visible header has a different heading. Accessibility
relies on the title being present; hide it with sr-only if the visual design omits it.