Skip to content
zedkit
@zedtech/zedkit-ui

Drawer

Slide-in panels from any edge: right-side detail on desktop, bottom sheet on mobile; size sm, md or lg.

beta@zedtech/zedkit-ui

Wraps: vaul

Direction

Right panel on wide screens, bottom sheet on phones (the default).

View props table
Who is it for?
Developers showing detail views beside a list without navigation.
When should I use it?
For list-detail previews and short side forms. Panel chrome (border, fill, edge shadow) comes from `Surface` elevation 3 (`shadow-overlay`); `size="sm" | "md" | "lg"` on `DrawerContent` sets desktop side width (`md` is the default 28rem; `lg` is about min(600px, 92vw)).
When should I pick something else?
For multi-step flows — use a full page or wizard instead.

Use it

Examples import from the package. With copied source, import from @/components/ui/drawer instead.

Right detail panel
import { Button, Drawer, DrawerClose, DrawerContent, DrawerTitle, DrawerTrigger } from "@zedtech/zedkit-ui";
<Drawer direction="right">
  <DrawerTrigger asChild><Button>Open</Button></DrawerTrigger>
  <DrawerContent>
    <DrawerClose asChild><Button variant="ghost" size="sm">Close</Button></DrawerClose>
    <DrawerTitle>Details</DrawerTitle>
  </DrawerContent>
</Drawer>

Bottom sheet

import { Button, Drawer, DrawerContent, DrawerHandle, DrawerTitle, DrawerTrigger } from "@zedtech/zedkit-ui";
<Drawer>
  <DrawerTrigger asChild><Button variant="outline">Filters</Button></DrawerTrigger>
  <DrawerContent>
    <DrawerHandle />
    <DrawerTitle>Filters</DrawerTitle>
  </DrawerContent>
</Drawer>

Side panel on every screen

import { Button, Drawer, DrawerBody, DrawerCloseButton, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from "@zedtech/zedkit-ui";
<Drawer direction="left" mobile="side">
  <DrawerTrigger asChild><Button variant="outline">Menu</Button></DrawerTrigger>
  <DrawerContent>
    <DrawerHeader>
      <DrawerTitle>Menu</DrawerTitle>
      <DrawerCloseButton />
    </DrawerHeader>
    <DrawerBody>Links</DrawerBody>
  </DrawerContent>
</Drawer>

Kit not installed yet?

You get
Every component from one import, with the theme tokens included. Updates arrive with your package manager.
You need
  • React 19 and Tailwind CSS 4, for example a Next.js app created with the Tailwind option.
  1. Install

    Terminal
    pnpm add @zedtech/zedkit-ui @fontsource-variable/inter @fontsource-variable/space-grotesk
  2. Load the styles

    Tailwind does not scan node_modules, so the @source line points it at the kit's class names. The path is relative to this file.

    src/app/globals.cssReplace the contents
    @import "tailwindcss";
    @import "@zedtech/zedkit-ui/styles.css";
    @source "../../node_modules/@zedtech/zedkit-ui/src/**/*.{ts,tsx}";
    @source not "../../node_modules/@zedtech/zedkit-ui/src/**/*.test.*";
    
  3. Pick a look

    Set data-identity="glass" on <html> so the finished app matches the site. Fresh app: replace src/app/layout.tsx. Existing app: merge, and keep ThemeProvider and other providers.

    src/app/layout.tsxReplace the contents
    import "./globals.css";
    import "./fonts";
    
    export default function RootLayout({ children }: { children: React.ReactNode }) {
      return (
        <html lang="en" data-identity="glass">
          <body>{children}</body>
        </html>
      );
    }
    
  4. Load the fonts

    The Glass look uses Inter and Space Grotesk; these imports self-host them.

    src/app/fonts.tsCreate the file
    import "@fontsource-variable/inter";
    import "@fontsource-variable/space-grotesk";
    
  5. Import and render

    src/app/page.tsxReplace the contents
    import { Button, Drawer, DrawerClose, DrawerContent, DrawerTitle, DrawerTrigger } from "@zedtech/zedkit-ui";
    
    export default function Page() {
      return (
        <main className="px-page-gutter py-section-sm">
          <Drawer direction="right">
            <DrawerTrigger asChild><Button>Open</Button></DrawerTrigger>
            <DrawerContent>
              <DrawerClose asChild><Button variant="ghost" size="sm">Close</Button></DrawerClose>
              <DrawerTitle>Details</DrawerTitle>
            </DrawerContent>
          </Drawer>
        </main>
      );
    }
    

Package version 2.0.1.

Props

Prop

Type

Accessibility

Modal drawers use Vaul / Radix Dialog: focus lands on the panel itself on open (never a field, never a text selection) so the focus trap engages; initialFocus (a ref or a selector) opts a field in, with the caret at the end. Escape to close and focus returns to the trigger; rest of the page is hidden from assistive tech while open (role="dialog"). modal={false} (and matching DrawerContent) renders a kit inline panel with Surface styling—not Vaul/Radix—so the page stays pointer- and keyboard-reachable, without aria-hidden on siblings; mount autofocus stays off, Escape still closes and returns focus to the trigger. Provide DrawerTitle (and DrawerDescription when the panel needs context). Use DrawerCloseButton (44px touch target) plus DrawerHandle for swipe-down; the handle hides itself on left and right drawers and moves to the bottom edge of a top drawer. Every direction closes by dragging toward its edge, tapping the dimmed area, or pressing Escape on modal drawers. Safe-area insets are respected, and fields inside a drawer stay at 16px on touch screens. Sticky DrawerHeader / DrawerFooter keep title and actions visible; DrawerBody scrolls with overscroll-behavior: contain.

Troubleshooting

Dim overlay missing after `shadcn add` — install the drawer registry item (it injects the `--overlay` token) or add the token to your theme. `direction="right"` with default `mobile="sheet"` becomes a bottom sheet under 640px; pass `mobile="side"` to keep a full-height side panel on phones (up to 90% of the width, so the dimmed page stays tappable).

On this page