Skip to content

shadcn.io is an independent project built on shadcn/ui

Components

Free

Sheet for React Aria

Slide a panel in from any edge for a form or detail, leaving the page in sight. For React with React Aria, when a centered dialog would hide too much.

The panel is anchored to one edge of the screen, rather than floating over the center.

Use it when the task needs its own surface and the page underneath should stay in sight. A short confirmation fits better in a Dialog. In React, React Aria traps focus while the panel is open, and it can sit on any edge, including the bottom on a narrow screen.

Preview width

Installation

Sign in to get your install command
Free with an account. It carries your token, so the CLI installs everything in one go.

Anatomy

Sheet anatomy: content, close, title, description, footer
SheetTrigger
SheetOverlay
SheetPositioner
SheetContent
SheetTitle
SheetDescription
SheetClose

Usage

import { Button } from "@/components/ui/button";
import { Field, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import {
  Sheet, SheetClose, SheetDescription, SheetFooter, SheetHeader,
  SheetTitle, SheetTrigger,
} from "@/components/ui/sheet";
const SheetDemo = () => (
  <SheetTrigger>
    <Button variant="outline">Open</Button>
    <Sheet>
      <SheetHeader>
        <SheetTitle>Edit profile</SheetTitle>
        <SheetDescription>
          Make changes to your profile here. Click save when you&apos;re done.
        </SheetDescription>
      </SheetHeader>
      <div className="grid flex-1 auto-rows-min gap-6 px-4">
        <Field>
          <FieldLabel htmlFor="sheet-demo-name">Name</FieldLabel>
          <Input
            className="min-w-0 max-w-full"
            defaultValue="Pedro Duarte"
            id="sheet-demo-name"
            type="text"
          />
        </Field>
        <Field>
          <FieldLabel htmlFor="sheet-demo-username">Username</FieldLabel>
          <Input
            className="min-w-0 max-w-full"
            defaultValue="@peduarte"
            id="sheet-demo-username"
            type="text"
          />
        </Field>
      </div>
      <SheetFooter>
        <Button type="submit">Save changes</Button>
        <SheetClose variant="outline">Close</SheetClose>
      </SheetFooter>
    </Sheet>
  </SheetTrigger>
);

Accessibility

Enter
Activate the focused control.
Space
Activate the focused control.

Demos

Side

side on SheetContent is top, right, bottom, or left, with right as the default. Top and bottom are capped at half the viewport here, so a long form scrolls inside the panel. Use the bottom edge on a phone, and a side edge for an inspector next to a list. The title, the focus trap, and Escape stay the same on every edge.

Preview width

No Close Button

showCloseButton set to false removes the corner icon. This panel then has a title and a description, and no footer button, so the written hint is to click outside. Hide that icon only when another close control is obvious, usually next to the primary action. Escape still dismisses a modal sheet, and the overlay click is a backup rather than the thing you want people to hunt for.

Preview width

Rtl

The trigger is Arabic, and the panel opens from the left with dir set to rtl on SheetContent. Title, fields, and footer actions align to the start of the line. Put dir on the content, not only the trigger, because the panel is portaled and can miss the page direction. side is still an explicit edge and does not flip on its own.

Preview width

FAQ

How do I control whether a Sheet is open in React?

The sheet starts closed and opens from its trigger. Control it when another part of the page must open or close it. Keep that boolean in state and pass it back, or use the default prop for the first state only. Pass isOpen so onOpenChange receives the next boolean, set defaultOpen for the first state, and SheetTrigger wraps both the button and the Sheet.

How do I change which edge a Sheet uses?

Set side on SheetContent to top, right, bottom, or left. The default is right, and bottom slides up from the bottom edge, which suits a narrow screen. The Side demo shows all four edges. The sheet still traps focus the same way on every edge.

Why does a Sheet need a SheetTitle?

SheetTitle names the dialog for assistive tech, so always render one. If the design has no visible heading, hide the title with the sr-only utility and keep it in the tree. SheetDescription explains the task and is optional. Escape closes the sheet and returns focus to the trigger.

How do I hide the Sheet close button?

The close button is shown by default. Set showCloseButton to false on SheetContent to hide it, as the No Close Button demo does. Still offer a SheetClose in the footer, or people may not see how to dismiss it. Escape still closes a modal sheet.

How do I use a button as the Sheet trigger with React Aria?

The trigger should look like your button, not like an extra wrapper. Put the visible label on the button so the control has an accessible name. SheetTrigger wraps the button and the Sheet together, and the button is the first child. There is no asChild prop.

Should I use a Sheet, a Dialog, or a Drawer?

Use a Sheet when the panel should slide in from a screen edge and leave part of the page in view. Use a Dialog for a centered modal, such as a short confirmation. Use a Drawer when the panel should support swipe, usually from the bottom on a phone.

Why is my Sheet behind another layer, or clipping a long form?

Sheet content is portaled and stacked at z-50, so it sits above the page. If another overlay uses the same layer, edit the sheet file under components/ui and raise the overlay and content together. If a long form is clipped, let the body scroll, for example by wrapping it in a Scroll Area.

How do I install Sheet in React?

Run the command in the Installation section above. It adds Sheet and its parts to your ui folder. Import from that folder when the command finishes, instead of copying the source by hand, and rerun the command later if you want the latest files. The command uses the shadcn CLI.

API Reference

Sheet

data-slot="sheet-content"

PropType
defaultOpen?boolean

Whether the overlay is open by default (uncontrolled).

onOpenChange?(isOpen: boolean) → void

Handler that is called when the overlay's open state changes.

Parameters

isOpen – boolean

Returns
void
isDismissable?boolean

Whether to close the modal when the user interacts outside it.

Default
false
isEntering?boolean

Whether the modal is currently performing an entry animation.

isExiting?boolean

Whether the modal is currently performing an exit animation.

isKeyboardDismissDisabled?boolean

Whether pressing the escape key to close the modal should be disabled.

Default
false
isOpen?boolean

Whether the overlay is open by default (controlled).

onEnter?(element: HTMLElement) → void | Promise<void>

Callback when the modal starts entering. Return a promise to indicate when the entry animation has completed.

Type
(element: HTMLElement) → void | Promise<void>
Parameters

element – HTMLElement

Returns
void | Promise<void>
onExit?(element: HTMLElement) → void | Promise<void>

Callback when the modal starts exiting. Return a promise to indicate when the exit animation has completed.

Type
(element: HTMLElement) → void | Promise<void>
Parameters

element – HTMLElement

Returns
void | Promise<void>
overscrollPadding?boolean

Whether to add padding to the sheet so that it appears to continue outside the viewport.

shouldCloseOnInteractOutside?(element: Element) → boolean

When user interacts with the argument element outside of the overlay ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the overlay. By default, onClose will always be called on interaction outside the overlay ref.

Parameters

element – Element

Returns
boolean
showCloseButton?boolean

Show close button at the top right corner.

Default
true
side?"top" | "right" | "bottom" | "left"

Edge of the screen where the sheet appears.

Type
"top" | "right" | "bottom" | "left"
Default
"right"
slot?string | null

A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.

Type
string | null
stackAnimation?string

CSS @keyframes name for the animation that occurs when a sheet has descendants.

style?StyleOrFunction<T>

The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.

Type
StyleOrFunction<T>
swipeAnimation?string

CSS @keyframes name for the animation that occurs while the user swipes.

swipeAnimationRange?{ start?: number; end?: number; }

The snap point indices between which the swipe animation occurs. If omitted, the animation will occur over the full range of the sheet's movement.

Type
{ start?: number; end?: number; }
UNSTABLE_deferUntilEntered?boolean

Whether to wait until the entry animation completes before hiding content outside the modal and moving focus into it.

UNSTABLE_overrideFocus?boolean

Whether to override the focus() method so it does not scroll the page. This is temporary and will be removed after fully testing all overlays.

UNSTABLE_portalContainer?Element

The container element in which the overlay portal will be placed. This may have unknown behavior depending on where it is portalled to. Deprecated. - Use a parent UNSAFE_PortalProvider to set your portal container instead.

Default
document.body
render?DOMRenderFunction<E, T>

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

Type
DOMRenderFunction<E, T>
className?string

Merged with the part's classes.

AttributeType
data-side?string

Mirrors side.

SheetTrigger

data-slot="sheet-trigger"

PropType
defaultOpen?boolean

Whether the overlay is open by default (uncontrolled).

onOpenChange?(isOpen: boolean) → void

Handler that is called when the overlay's open state changes.

Parameters

isOpen – boolean

Returns
void
isOpen?boolean

Whether the overlay is open by default (controlled).

SheetClose

data-slot="sheet-close"

PropType
children?ReactNode

The content to display in the button.

clickEffect?boolean

Apply a click effect to the button.

Default
true
download?LinkPrimitiveProps["download"]

With href, downloads the linked file instead of opening it.

href?string

When set, the button renders as a link.

isDisabled?boolean

Whether the button is disabled.

isLoading?boolean

Show a loading indicator.

Default
false
rel?string

With href, the link's relationship to the page (noreferrer, …).

target?string

With href, where the linked page opens (_blank, …).

className?string

Merged with the part's classes.

SheetOverlay

data-slot="sheet-overlay"

PropType
defaultOpen?boolean

Whether the overlay is open by default (uncontrolled).

onOpenChange?(isOpen: boolean) → void

Handler that is called when the overlay's open state changes.

Parameters

isOpen – boolean

Returns
void
isDismissable?boolean

Whether to close the modal when the user interacts outside it.

Default
false
isEntering?boolean

Whether the modal is currently performing an entry animation.

isExiting?boolean

Whether the modal is currently performing an exit animation.

isKeyboardDismissDisabled?boolean

Whether pressing the escape key to close the modal should be disabled.

Default
false
isOpen?boolean

Whether the overlay is open by default (controlled).

onEnter?(element: HTMLElement) → void | Promise<void>

Callback when the modal starts entering. Return a promise to indicate when the entry animation has completed.

Type
(element: HTMLElement) → void | Promise<void>
Parameters

element – HTMLElement

Returns
void | Promise<void>
onExit?(element: HTMLElement) → void | Promise<void>

Callback when the modal starts exiting. Return a promise to indicate when the exit animation has completed.

Type
(element: HTMLElement) → void | Promise<void>
Parameters

element – HTMLElement

Returns
void | Promise<void>
position?"bottom" | "top" | "left" | "right" | "start" | "end" | "center"

The placement of the sheet on the screen. start and end are mirrored in right-to-left locales.

Type
"bottom" | "top" | "left" | "right" | "start" | "end" | "center"
Default
"bottom"
preventDismissal?boolean

Whether to prevent the user from closing the sheet by swiping, pressing Escape, or interacting outside it.

Default
false
shouldCloseOnInteractOutside?(element: Element) → boolean

When user interacts with the argument element outside of the overlay ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the overlay. By default, onClose will always be called on interaction outside the overlay ref.

Parameters

element – Element

Returns
boolean
slot?string | null

A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.

Type
string | null
snapPoints?Array<number | string>

Snap points the sheet will stop at, expressed as the amount of the sheet that is visible. Numbers are pixels, and percentages are relative to the size of the sheet. Sheets initially open to the first snap point.

Type
Array<number | string>
style?StyleOrFunction<T>

The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.

Type
StyleOrFunction<T>
swipeDirection?"bottom" | "top" | "vertical" | "left" | "right" | "start" | "end" | "horizontal"

The direction the sheet can be swiped. start and end are mirrored in right-to-left locales. Defaults to the same direction as position.

Type
"bottom" | "top" | "vertical" | "left" | "right" | "start" | "end" | "horizontal"
UNSTABLE_deferUntilEntered?boolean

Whether to wait until the entry animation completes before hiding content outside the modal and moving focus into it.

UNSTABLE_overrideFocus?boolean

Whether to override the focus() method so it does not scroll the page. This is temporary and will be removed after fully testing all overlays.

UNSTABLE_portalContainer?Element

The container element in which the overlay portal will be placed. This may have unknown behavior depending on where it is portalled to. Deprecated. - Use a parent UNSAFE_PortalProvider to set your portal container instead.

Default
document.body
render?DOMRenderFunction<E, T>

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

Type
DOMRenderFunction<E, T>
className?string

Merged with the part's classes.

SheetContent

PropType
defaultOpen?boolean

Whether the overlay is open by default (uncontrolled).

onOpenChange?(isOpen: boolean) → void

Handler that is called when the overlay's open state changes.

Parameters

isOpen – boolean

Returns
void
isDismissable?boolean

Whether to close the modal when the user interacts outside it.

Default
false
isEntering?boolean

Whether the modal is currently performing an entry animation.

isExiting?boolean

Whether the modal is currently performing an exit animation.

isKeyboardDismissDisabled?boolean

Whether pressing the escape key to close the modal should be disabled.

Default
false
isOpen?boolean

Whether the overlay is open by default (controlled).

onEnter?(element: HTMLElement) → void | Promise<void>

Callback when the modal starts entering. Return a promise to indicate when the entry animation has completed.

Type
(element: HTMLElement) → void | Promise<void>
Parameters

element – HTMLElement

Returns
void | Promise<void>
onExit?(element: HTMLElement) → void | Promise<void>

Callback when the modal starts exiting. Return a promise to indicate when the exit animation has completed.

Type
(element: HTMLElement) → void | Promise<void>
Parameters

element – HTMLElement

Returns
void | Promise<void>
overscrollPadding?boolean

Whether to add padding to the sheet so that it appears to continue outside the viewport.

role?"dialog" | "alertdialog"

The accessibility role for the dialog.

Type
"dialog" | "alertdialog"
Default
"dialog"
shouldCloseOnInteractOutside?(element: Element) → boolean

When user interacts with the argument element outside of the overlay ref, return true if onClose should be called. This gives you a chance to filter out interaction with elements that should not dismiss the overlay. By default, onClose will always be called on interaction outside the overlay ref.

Parameters

element – Element

Returns
boolean
showCloseButton?boolean

Show close button at the top right corner.

Default
true
side?"top" | "right" | "bottom" | "left"

Edge of the screen where the sheet appears.

Type
"top" | "right" | "bottom" | "left"
Default
"right"
slot?string | null

A slot name for the component. Slots allow the component to receive props from a parent component. An explicit null value indicates that the local props completely override all props received from a parent.

Type
string | null
stackAnimation?string

CSS @keyframes name for the animation that occurs when a sheet has descendants.

style?StyleOrFunction<T>

The inline [style](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style) for the element. A function may be provided to compute the style based on component state.

Type
StyleOrFunction<T>
swipeAnimation?string

CSS @keyframes name for the animation that occurs while the user swipes.

swipeAnimationRange?{ start?: number; end?: number; }

The snap point indices between which the swipe animation occurs. If omitted, the animation will occur over the full range of the sheet's movement.

Type
{ start?: number; end?: number; }
UNSTABLE_deferUntilEntered?boolean

Whether to wait until the entry animation completes before hiding content outside the modal and moving focus into it.

UNSTABLE_overrideFocus?boolean

Whether to override the focus() method so it does not scroll the page. This is temporary and will be removed after fully testing all overlays.

UNSTABLE_portalContainer?Element

The container element in which the overlay portal will be placed. This may have unknown behavior depending on where it is portalled to. Deprecated. - Use a parent UNSAFE_PortalProvider to set your portal container instead.

Default
document.body
render?DOMRenderFunction<E, T>

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

Type
DOMRenderFunction<E, T>
className?string

Merged with the part's classes.

SheetHeader

<div> data-slot="sheet-header"

PropType
description?string

The description of the sheet.

title?string

The title of the sheet.

className?string

Merged with the part's classes.

SheetFooter

<div> data-slot="sheet-footer"

PropType
className?string

Merged with the part's classes.

SheetTitle

PropType
level?number

The heading level.

Default
3
render?DOMRenderFunction<E, T>

Overrides the default DOM element with a custom render function. This allows rendering existing components with built-in styles and behaviors such as router links, animation libraries, and pre-styled components. Requirements: - You must render the expected element type (e.g. if <button> is expected, you cannot render an <a>). - Only a single root DOM element can be rendered (no fragments). - You must pass through props and ref to the underlying DOM element, merging with your own prop as appropriate.

Type
DOMRenderFunction<E, T>
className?string

Merged with the part's classes.

SheetDescription

<div>

PropType
className?string

Merged with the part's classes.