O
Orbit Design

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 classes

ResponsiveSheet

openboolean — controlled open state
onOpenChange(open: boolean) => void — change handler
modalboolean — 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