Drawer components

Powerful and customizable React drawer components built for modern applications and websites. These drawers are built using React Aria and styled with Tailwind CSS.

Installation

You can add this drawer component using our CLI or manually:

npx untitledui@latest add slideout-menu

Drawers examples

Below are examples and variations of this drawers component:

API reference

Import the parts and assemble them:

import { Dialog, Modal, ModalOverlay, SlideoutMenu } from "@/components/application/slideout-menus/slideout-menu";
 
<SlideoutMenu>
    <SlideoutMenu.Header />
    <SlideoutMenu.Content />
    <SlideoutMenu.Footer />
</SlideoutMenu>
 
<ModalOverlay>
    <Modal>
        <Dialog />
    </Modal>
</ModalOverlay>

Dialog

Renders React Aria’s Dialog — all of its props are supported.

Dialog props
PropTypeDefaultDescription
childrenReactNode | ((opts: DialogRenderProps) => ReactNode)—Children of the dialog. A function may be provided to access a function to close the dialog.
idstring—The element's unique identifier.
Styling (4)
Dialog styling props
PropTypeDefaultDescription
slotstring | 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.
classNamestring—The CSS className for the element.
renderDOMRenderFunction<"section", undefined>—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.
styleCSSProperties—The inline style for the element.
Accessibility (5)
Dialog accessibility props
PropTypeDefaultDescription
aria-describedbystring—Identifies the element (or elements) that describes the object.
aria-detailsstring—Identifies the element (or elements) that provide a detailed, extended description for the object.
aria-labelstring"Slideout menu"Defines a string value that labels the current element.
aria-labelledbystring—Identifies the element (or elements) that labels the current element.
role
"dialog""alertdialog"
"dialog"The accessibility role for the dialog.

Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.

FiltersAdvancedMenu

Import FiltersAdvancedMenu from @/components/application/slideout-menus/filters-advanced-menu. Renders SlideoutMenu.

FiltersAdvancedMenu props
PropTypeDefaultDescription
defaultFiltersFilterRow[]—Filter rows the menu starts with. Leave empty to open with no rows, then let the user add them.

SlideoutMenu

Renders ModalOverlay.

SlideoutMenu props
PropTypeDefaultDescription
children* (required)ReactNode | ((children: AriaModalRenderProps & { close: () => void; }) => ReactNode)—The content of the menu. Can be a render prop that receives the modal state along with a close function.
dialogClassNamestring—The class name applied to the inner dialog, while className styles the sliding panel.
Props from React Aria Components (12)
SlideoutMenu inherited props
PropTypeDefaultDescription
defaultOpenboolean—Whether the overlay is open by default (uncontrolled).
isDismissablebooleanfalseWhether to close the modal when the user interacts outside it.
isEnteringboolean—Whether the modal is currently performing an entry animation.
isExitingboolean—Whether the modal is currently performing an exit animation.
isKeyboardDismissDisabledbooleanfalseWhether pressing the escape key to close the modal should be disabled.
isOpenboolean—Whether the overlay is open by default (controlled).
onOpenChange((isOpen: boolean) => void)—Handler that is called when the overlay's open state changes.
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.
styleStyleOrFunction<AriaModalRenderProps>—The inline style for the element. A function may be provided to compute the style based on component state.
slotstring | 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.
classNameClassNameOrFunction<AriaModalRenderProps>—The CSS className for the element. A function may be provided to compute the class based on component state.
renderDOMRenderFunction<"div", AriaModalRenderProps>—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.

Also accepts the global HTML attributes (dir, lang, hidden, inert, translate), all standard React DOM event handlers.

SlideoutMenu.Content

Renders a <div> element.

Also accepts all standard HTML attributes, all aria-* attributes, all standard React DOM event handlers.

SlideoutMenu.Header

Renders a <header> element.

SlideoutMenu.Header props
PropTypeDefaultDescription
onClose(() => void)—Handler called when the close button in the top right corner is pressed.

Also accepts all standard HTML attributes, all aria-* attributes, all standard React DOM event handlers.

SlideoutMenu.Trigger

Renders React Aria’s DialogTrigger — all of its props are supported.

SlideoutMenu.Trigger props
PropTypeDefaultDescription
children* (required)ReactNode——
isOpenboolean—Whether the overlay is open by default (controlled).
defaultOpenboolean—Whether the overlay is open by default (uncontrolled).
onOpenChange((isOpen: boolean) => void)—Handler that is called when the overlay's open state changes.

FAQs

Please refer to our frequently asked questions page for more.

The drawer is exported as SlideoutMenu and is built on React Aria's modal primitives, so it takes the same open-state props. For a controlled drawer, pass isOpen and onOpenChange; for an uncontrolled one, wrap a trigger button and the drawer in SlideoutMenu.Trigger (React Aria's DialogTrigger) and let it manage state. Add isDismissable to close the drawer when the user clicks the overlay.

SlideoutMenu is a compound component with SlideoutMenu.Header for the title area, SlideoutMenu.Content for the scrollable body, SlideoutMenu.Footer for pinned actions, and SlideoutMenu.Trigger for the uncontrolled pattern. The ModalOverlay, Modal, and Dialog pieces it composes are exported from the same file if you need to assemble a custom layout.

SlideoutMenu.Header always renders a small CloseButton in its top-right corner, but it only does something when you pass onClose, for example onClose={() => setIsOpen(false)} or the close function from the drawer's render-function children. Everything you pass as children renders beneath it, so a featured icon, title and supporting text all sit in the header.

Pass a render function as the drawer's children instead of elements. It receives the React Aria modal render props plus a close function: <SlideoutMenu>{({ close }) => <Button onClick={close}>Cancel</Button>}</SlideoutMenu>. This is handy for footer actions that need to dismiss the drawer without lifting state.

Yes. The panel defaults to w-full max-w-100, sits flush against the right edge for the full viewport height, and both className and dialogClassName are merged with the built-in classes — className targets the overlay and sliding panel, while dialogClassName targets the inner dialog (the examples use dialogClassName="gap-0" to remove the default spacing between header, content, and footer).

It slides in from the right. The panel animates with slide-in-from-right over 300ms on enter and slide-out-to-right over 500ms on exit, while the translucent overlay behind it fades in and out over the same intervals.

It is built on React Aria's Modal and Dialog, so focus is trapped inside the panel while it is open, focus returns to the trigger on close, and pressing Escape dismisses it. Set isKeyboardDismissDisabled to opt out. The dialog renders with role="dialog" and a default aria-label, and SlideoutMenu.Content renders with role="main" by default, which you can override with the role prop.