Drawer

A panel that slides in from an edge (Base UI Dialog behavior).

Real use · navigation drawer

Header + Footer · sticky, scrolling content

Using Drawer

Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.

Plain HTML — CSS classes

The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so Drawer is styled but inert: its behavior comes from modal. For that behavior with no framework, use the node-tree path below.

/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";

Root class drawer-backdrop, with 7 modifiers:

  • .drawer-backdrop
  • .drawer-description
  • .drawer-footer
  • .drawer-footer-sticky
  • .drawer-header
  • .drawer-header-sticky
  • .drawer-popup
  • .drawer-title

React

Typed components over those same classes, with behavior and accessibility from Base UI.

npm i @wizeworks/silicaui-react
import { Drawer } from "@wizeworks/silicaui-react";

Props

DrawerContentProps
PropTypeRequiredDescription
childrenReact.ReactNodeno—
sideDrawerSidenoEdge the drawer slides from. Default left.
backdropClassNamestringnoClass for the backdrop layer.
DrawerHeaderProps
PropTypeRequiredDescription
stickybooleannoPin this bar in place while the rest of the content scrolls.
DrawerFooterProps
PropTypeRequiredDescription
stickybooleannoPin this bar in place while the rest of the content scrolls.

Source of the demo above

The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.

Show source
import {
    Drawer,
    DrawerTrigger,
    DrawerClose,
    DrawerContent,
    DrawerTitle,
    DrawerDescription,
    DrawerHeader,
    DrawerFooter,
    Button,
} from "@wizeworks/silicaui-react";
import { Section, Row } from "../lib/Section";

export function DrawerDemo() {
    return (
        <>
            <Section title="Real use · navigation drawer">
                <Row>
                    {(["left", "right", "top", "bottom"] as const).map((side) => (
                        <Drawer key={side}>
                            <DrawerTrigger>
                                <Button variant="outline" color="neutral">
                                    {side}
                                </Button>
                            </DrawerTrigger>
                            <DrawerContent side={side}>
                                <DrawerTitle>Navigation</DrawerTitle>
                                <DrawerDescription>
                                    Slides in from the {side} edge.
                                </DrawerDescription>
                                <nav className="flex flex-col gap-2 py-4 text-sm">
                                    <a href="#">Dashboard</a>
                                    <a href="#">Projects</a>
                                    <a href="#">Settings</a>
                                </nav>
                                <DrawerClose>
                                    <Button variant="ghost" color="neutral">
                                        Close
                                    </Button>
                                </DrawerClose>
                            </DrawerContent>
                        </Drawer>
                    ))}
                </Row>
            </Section>

            <Section title="Header + Footer · sticky, scrolling content">
                <Drawer>
                    <DrawerTrigger>
                        <Button variant="outline">Filters (sticky header/footer)</Button>
                    </DrawerTrigger>
                    <DrawerContent side="right">
                        <DrawerHeader sticky>
                            <DrawerTitle>Filters</DrawerTitle>
                            <DrawerClose>
                                <Button variant="ghost" shape="circle" size="sm">
                                    ✕
                                </Button>
                            </DrawerClose>
                        </DrawerHeader>
                        <div className="flex flex-col gap-3 text-sm">
                            {Array.from({ length: 14 }, (_, i) => (
                                <label key={i} className="flex items-center gap-2">
                                    <input type="checkbox" /> Filter option {i + 1}
                                </label>
                            ))}
                        </div>
                        <DrawerFooter sticky>
                            <DrawerClose>
                                <Button variant="ghost" color="neutral">
                                    Reset
                                </Button>
                            </DrawerClose>
                            <DrawerClose>
                                <Button>Apply</Button>
                            </DrawerClose>
                        </DrawerFooter>
                    </DrawerContent>
                </Drawer>
            </Section>
        </>
    );
}

Vanilla — node tree to HTML

Drawer — identical shape to Dialog; props.side becomes a data-side attribute on the panel for the CSS to slide from (render-neutral to the behavior itself). Build a node tree, project it with toHtml(), and let the zero-dependency runtime hydrate it. This is the path for generated or user-authored documents — a site builder, CMS output, a static export.

npm i @wizeworks/silicaui-html @wizeworks/silicaui-behaviors
import { atom, toHtml } from "@wizeworks/silicaui-html";

const node = atom("Drawer", "drawer-backdrop", { /* props */ }, [/* children */]);
const markup = toHtml(node);

Styling on this path is the class string in the second argument — the same classes as the Plain HTML section above. There is no color prop here; write "drawer-backdrop drawer-backdrop-primary" rather than passing a colour as a prop.

Takes children
yes
Hydrated by
modal

Load @wizeworks/silicaui-behaviors on the page or this markup renders correctly and does nothing.

The full API for Drawer, on every path, is available through the Silica MCP server.