Summit
ComponentsOverlays

Drawer

A Drawer is a panel that slides in from an edge of the screen and that users can close with a swipe.

When to Use

  • for a short task on a touch screen that users swipe away, such as “Log time”
  • for a panel that rests at set heights, which you list in snapPoints

When Not to Use

  • for a side panel that needs no swipe (use a Sheet)
  • for a short form in the center of the screen (use a Dialog)

See Dialog for a comparison of the Dialog, the Alert Dialog, the Sheet, and the Drawer.

Anatomy

ElementUsage
OverlayShown when modal
PopupRequired
HandleOptional
Title*Required
DescriptionOptional
FooterOptional

* The title is the Drawer’s accessible name. If the design shows no title, visually hide it and keep it in the markup.

DrawerContent renders the portal, the overlay, and the popup, and showSwipeHandle on Drawer adds the handle. A Drawer has no close button, so place a DrawerClose in its footer. The Buttons in the footer are stacked in the order in which they are written, so write the main action first.

A top or bottom Drawer spans the screen. In the preview, a wrapper with max-w-sm limits its content to 384px.

Behavior

By default, a Drawer is modal: focus stays in the popup, and the page’s scroll is locked. If you want the page to stay interactive, set modal={false} on Drawer, which also removes the overlay. If you want the Drawer to stay open when users click the overlay, set disablePointerDismissal on Drawer.

When a Drawer opens, focus is moved to the popup, not to its first control, and users reach that control with Tab. If you want to change the target, use initialFocus on DrawerContent.

Position and Size

To set the edge of the Drawer and the direction of the swipe that closes it, use swipeDirection on Drawer.

DirectionPositionSize
down, upThe bottom or the top edge, across the screenAs tall as its content, up to the height of the screen minus 96px
left, rightThat edge, from the top to the bottom384px wide from 640px, and 75% of the screen below 640px

If floating is set on Drawer, the Drawer is inset from the edges of the screen. See Layout for the widths of the other overlays.

swipeDirection is physical: left is the left edge in both directions. See Right-to-Left for how to read the direction.

Swipe

On a touch screen, users can start the swipe inside the content. Mouse users drag the handle to move the Drawer because a drag inside the content selects text. If you want to prevent a swipe that starts on an element from moving the Drawer, set data-base-ui-swipe-ignore on that element.

If showSwipeHandle is set, the handle is displayed on the open edge. The handle is hidden from assistive technology and can’t receive focus.

Snap Points

To set the heights at which a top or bottom Drawer rests, pass a list to snapPoints on Drawer. A number from 0 to 1 is a fraction of the height of the screen, a larger number is a height in pixels, and a string can use px or rem. The popup is then as tall as the screen minus 96px, and a point of 1 shows all of it.

The Drawer opens at the first point. A swipe moves it to another point, and a swipe down from the lowest point closes it.

Overflow

If the content is taller than the Drawer, it scrolls under the handle. To keep the header and the footer in view, see Scroll Long Content.

Accessibility

Base UI’s Drawer sets the role, keeps focus in the popup, and closes when users press Escape. You provide the title and a Button that closes the Drawer.

A Drawer needs a DrawerTitle so that screen readers can announce what it is for, as WCAG 2.2 SC 4.1.2 Name, Role, Value requires.

A Drawer with snapPoints needs a Button that sets snapPoint so that users who can’t drag can move between the points, as WCAG 2.2 SC 2.5.7 Dragging Movements requires. A drag is the only built-in way to move between them.

Keep a DrawerClose in the popup. The overlay and the handle are hidden from assistive technology, so screen reader users on a touch screen have no other way to close the Drawer.

DoPlace a DrawerClose in the footer, such as “Cancel”, as a Drawer has no close button.
Don’tWhen “Save” is the only Button, screen reader users on a touch screen have no way to close the Drawer without saving.

Installation

npx shadcn@latest add @summit/drawer

Usage

import { Button } from '@/components/ui/button';
import {
    Drawer,
    DrawerClose,
    DrawerContent,
    DrawerDescription,
    DrawerFooter,
    DrawerHeader,
    DrawerTitle,
    DrawerTrigger,
} from '@/components/ui/drawer';

<Drawer>
    <DrawerTrigger render={<Button variant="outline" />}>Log time</DrawerTrigger>
    <DrawerContent>
        <DrawerHeader>
            <DrawerTitle>Log time</DrawerTitle>
            <DrawerDescription>Add the hours you worked on this project today.</DrawerDescription>
        </DrawerHeader>
        <DrawerFooter>
            <DrawerClose render={<Button />}>Save</DrawerClose>
            <DrawerClose render={<Button variant="outline" />}>Cancel</DrawerClose>
        </DrawerFooter>
    </DrawerContent>
</Drawer>;

Choose the Edge

Set swipeDirection, showSwipeHandle, and floating on Drawer, not on DrawerContent.

Choose the Edge
<Drawer swipeDirection="right" showSwipeHandle floating>
    <DrawerContent>
        <DrawerTitle>Filters</DrawerTitle>
    </DrawerContent>
</Drawer>

Set Snap Points

To move the Drawer from a Button, keep the current point in the parent with snapPoint and onSnapPointChange.

Set Snap Points
import { useState } from 'react';

const points = ['148px', 1];
const [point, setPoint] = useState<number | string | null>(points[0]);

<Drawer snapPoints={points} snapPoint={point} onSnapPointChange={setPoint}>
    <DrawerContent>
        <DrawerHeader>
            <DrawerTitle>Timer</DrawerTitle>
        </DrawerHeader>
        <Button variant="ghost" onClick={() => setPoint(1)}>
            Show all entries
        </Button>
    </DrawerContent>
</Drawer>;

Scroll Long Content

To scroll long content, add flex-1 and overflow-y-auto to the content between the header and the footer. The footer then stays at the bottom of the Drawer.

Scroll Long Content
<DrawerContent>
    <DrawerHeader>
        <DrawerTitle>Log time</DrawerTitle>
    </DrawerHeader>
    <div className="flex-1 overflow-y-auto p-4">{entries}</div>
    <DrawerFooter>
        <DrawerClose render={<Button />}>Save</DrawerClose>
    </DrawerFooter>
</DrawerContent>

API Reference

DrawerContent passes its props and its className to the popup, and its children to the content inside it. The parts accept the props of their matching parts in Base UI’s Drawer, where DrawerOverlay is Drawer.Backdrop. DrawerHeader, DrawerFooter, and DrawerSwipeHandle accept the props of a div.

Drawer

PropTypeDefaultDescription
swipeDirection'down' | 'up' | 'left' | 'right''down'The edge of the Drawer and the direction of the swipe that closes it
modalboolean | 'trap-focus'trueLocks the page behind the Drawer. The overlay is rendered only when it is true.
showSwipeHandlebooleanfalseAdds the handle to the open edge
floatingbooleanfalseInsets the Drawer from the edges of the screen and rounds it
snapPoints(number | string)[]NoneThe heights at which a top or bottom Drawer rests

Other props are passed to the root of Base UI’s Drawer. See the Base UI Drawer documentation for open, onOpenChange, snapPoint, onSnapPointChange, and disablePointerDismissal.

On this page