overlay
Drawer
A dialog that enters from an edge, for navigation and side panels.
Examples
All four edges
A Dialog wearing a different surface — the same focus trap, scroll lock and dismiss stack, so the two can only differ in looks.
Own the source
Noksha ships as a package and as copy-paste source. Take the files and they are yours to change. These are read from the generated registry, so they are exactly what the library ships — never a paraphrase of it.
Take these files, and dialog, internal helpers along with them — the imports below point at them. Or let the CLI do it: npx @noksha-ui/cli add drawer writes them, follows the same dependency graph, and fixes up the imports.
import * as React from 'react';
import {
DialogBody,
DialogClose,
DialogDescription,
DialogFooter,
DialogHeader,
DialogRoot,
DialogSurface,
DialogTitle,
DialogTrigger,
} from '../dialog/dialog.js';
import type { DrawerContentProps } from './drawer.types.js';
import { drawerContentVariants } from './drawer.variants.js';
/**
* A panel that slides in from an edge of the screen.
*
* ```tsx
* <Drawer.Root>
* <Drawer.Trigger asChild><Button>Filters</Button></Drawer.Trigger>
* <Drawer.Content side="right" size="lg">
* <Drawer.Header><Drawer.Title>Filters</Drawer.Title></Drawer.Header>
* <Drawer.Body>…</Drawer.Body>
* </Drawer.Content>
* </Drawer.Root>
* ```
*
* It is a Dialog wearing a different surface, and it says so: the trap, the
* scroll lock, the dismiss stack and the labelling all come from the same
* implementation, so the two can never drift apart in behaviour — only in looks.
*/
export const DrawerContent = React.forwardRef<HTMLDivElement, DrawerContentProps>(
function DrawerContent({ side = 'right', size = 'md', className, ...rest }, ref) {
return (
<DialogSurface
ref={ref}
// The panel positions itself against its edge, so there is nothing for
// a centring layer to do — `display: contents` keeps it out of the way.
positionerClassName="contents"
surfaceClassName={drawerContentVariants({ side, size, className })}
{...rest}
/>
);
},
);
DrawerContent.displayName = 'Drawer.Content';
/**
* Flat aliases for the parts Drawer borrows from Dialog.
*
* A React Server Component cannot reach through the `Drawer` namespace below —
* a `"use client"` module's exports arrive as opaque client references, and
* `Drawer.Root` on one of those is `undefined`, not a component. Every other
* compound component in the library already ships this flat form; without it,
* Drawer would be the one component unusable from a server file.
*/
export {
DialogBody as DrawerBody,
DialogClose as DrawerClose,
DialogDescription as DrawerDescription,
DialogFooter as DrawerFooter,
DialogHeader as DrawerHeader,
DialogRoot as DrawerRoot,
DialogTitle as DrawerTitle,
DialogTrigger as DrawerTrigger,
} from '../dialog/dialog.js';
/** The namespace form, for client components. */
export const Drawer = {
Root: DialogRoot,
Trigger: DialogTrigger,
Content: DrawerContent,
Header: DialogHeader,
Title: DialogTitle,
Description: DialogDescription,
Body: DialogBody,
Footer: DialogFooter,
Close: DialogClose,
};
export { drawerContentVariants };API reference
Accepted values
- DrawerSide
toprightbottomleft- DrawerSize
smmdlgxlfull
DrawerContentProps
Also accepts everything from Omit<DialogContentProps, 'size'>.
| Prop | Type | Description |
|---|---|---|
| side | DrawerSide | Which edge it slides in from. |
| size | DrawerSize | Width for a left/right drawer, height for a top/bottom one. |