ResponsiveSheet
A responsive overlay that renders as a bottom drawer on mobile and a centered dialog on desktop. One component, two experiences.
Mobile-firstResponsive
How It Works
The component uses a single DOM tree with CSS media queries to switch between presentations:
< 768px
Bottom Drawer
Slides up from bottom, full-width, drag-to-dismiss feel
≥ 768px
Centered Dialog
Centered modal with backdrop, close on overlay click
Default
Preview
Glass Variant
Preview
Installation
npx orbit-design add responsive-sheet
Usage
import {
ResponsiveSheet,
ResponsiveSheetTrigger,
ResponsiveSheetContent,
ResponsiveSheetHeader,
ResponsiveSheetFooter,
ResponsiveSheetTitle,
ResponsiveSheetDescription,
ResponsiveSheetClose,
} from "@/components/orbit-ui/responsive-sheet"
export default function Page() {
return (
<ResponsiveSheet>
<ResponsiveSheetTrigger asChild>
<Button>Open</Button>
</ResponsiveSheetTrigger>
<ResponsiveSheetContent>
<ResponsiveSheetHeader>
<ResponsiveSheetTitle>Title</ResponsiveSheetTitle>
<ResponsiveSheetDescription>Description</ResponsiveSheetDescription>
</ResponsiveSheetHeader>
<div className="px-6 py-4">
{/* Your content */}
</div>
<ResponsiveSheetFooter>
<ResponsiveSheetClose asChild>
<Button variant="outline">Cancel</Button>
</ResponsiveSheetClose>
<Button>Confirm</Button>
</ResponsiveSheetFooter>
</ResponsiveSheetContent>
</ResponsiveSheet>
)
}CSS Setup
Add the responsive positioning styles to your global CSS file:
/* Mobile: bottom drawer */
.orbit-rs-content {
bottom: 0; left: 0; right: 0; top: auto;
width: 100%; max-height: 85vh;
border-radius: var(--orbit-radius) var(--orbit-radius) 0 0;
overflow-y: auto;
--tw-enter-translate-y: 100%;
--tw-exit-translate-y: 100%;
}
/* Desktop: centered dialog */
@media (min-width: 768px) {
.orbit-rs-content {
bottom: auto; left: 50%; right: auto; top: 50%;
min-width: 400px; max-width: 540px;
border-radius: var(--orbit-radius);
transform: translate(-50%, -50%);
--tw-enter-translate-y: 0;
--tw-enter-scale: 0.95;
--tw-enter-opacity: 0;
}
}API Reference
ResponsiveSheetContent
variant"default" | "glass" — defaults to "default"classNamestring — additional CSS classesResponsiveSheet
openboolean — controlled open stateonOpenChange(open: boolean) => void — change handlermodalboolean — whether to render as modal (default: true)Sub-components
- ResponsiveSheetTrigger
- ResponsiveSheetContent
- ResponsiveSheetHeader
- ResponsiveSheetFooter
- ResponsiveSheetTitle
- ResponsiveSheetDescription
- ResponsiveSheetClose
Dependencies
@radix-ui/react-dialog
class-variance-authority
lucide-react
Installed automatically when running npx orbit-design add responsive-sheet