Live Code
Storybook
Usage
Drawer
The Drawer component is a container that slides in from side of the screen. It can be used to display additional content or actions that are not part of the main view.
The Drawer is a composition of several subcomponents:
Drawer
const [isOpen, setOpen] = useState(false);
<Drawer id="drawer-dialog-example" isOpen={isOpen} onClose={() => setOpen(false)} aria-label="Drawer">
{/* Drawer Panel goes here */}
</Drawer>;
Alignment
The Drawer component allows aligning the content panel horizontally to the left or right side of the screen using alignmentX prop. By default, the drawer content panel is aligned to the right.
<Drawer id="drawer-dialog-example" isOpen={isOpen} onClose={() => setOpen(false)} alignmentX="left" aria-label="Drawer">
{/* Drawer Panel goes here */}
</Drawer>
Close on Backdrop Click
By default, the drawer will close when the backdrop is clicked. You can disable this behavior by setting the closeOnBackdropClick prop to false.
<Drawer
id="drawer-dialog-example"
isOpen={isOpen}
onClose={() => setOpen(false)}
closeOnBackdropClick={false}
aria-label="Drawer"
>
{/* Drawer content goes here */}
</Drawer>
Close on Escape Key Down
By default, the drawer will close when the escape key is pressed. You can disable this behavior by setting the closeOnEscapeKeyDown prop to false.
<Drawer
id="drawer-dialog-example"
isOpen={isOpen}
onClose={() => setOpen(false)}
closeOnEscapeKeyDown={false}
aria-label="Drawer"
>
{/* Drawer content goes here */}
</Drawer>
API
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
| alignmentX | left | right | right | ✕ | Drawer horizontal alignment |
| children | ReactNode | — | ✕ | Children node |
| closeOnBackdropClick | bool | true | ✕ | Whether the drawer will close when backdrop is clicked |
| closeOnEscapeKeyDown | bool | true | ✕ | Whether the drawer will close when escape key is pressed |
| id | string | — | ✓ | ID to be linked |
| isOpen | bool | false | ✓ | Open state |
| onClose | (event: ClickEvent or KeyboardEvent) => void | — | ✓ | Callback for drawer when closed |
The component further inherits properties from the <dialog> element.
On top of the API options, the components accept additional attributes. If you need more control over the styling of a component, you can use style props and escape hatches.
DrawerPanel
The DrawerPanel component is a container for the content that will be displayed in the drawer. It is composed from the DrawerPanelHeader and DrawerPanelBody sub-components.
<DrawerPanel>
<DrawerPanelHeader>
<CloseButton
size="large"
aria-expanded={isOpen}
aria-controls="drawer-dialog-example"
onClick={() => setOpen(false)}
/>
</DrawerPanelHeader>
<DrawerPanelBody hasSpacing>{/* Drawer content goes here */}</DrawerPanelBody>
</DrawerPanel>
API
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
| children | ReactNode | — | ✕ | Children node |
| elementType | ElementType | div | ✕ | Type of element used as drawer panel |
DrawerPanelHeader
The DrawerPanelHeader component is a container rendered at the top of the DrawerPanel. It is typically used to hold the CloseButton.
<DrawerPanelHeader>
<CloseButton
size="large"
aria-expanded={isOpen}
aria-controls="drawer-dialog-example"
onClick={() => setOpen(false)}
/>
</DrawerPanelHeader>
API
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
| children | ReactNode | — | ✕ | Children node |
On top of the API options, the components accept additional attributes. If you need more control over the styling of a component, you can use style props and escape hatches.
CloseButton
Pass the shared CloseButton inside DrawerPanelHeader. It is not wired up automatically, so provide:
- onClick — your drawer's onClose handler
- aria-controls — the drawer's id
- aria-expanded — the drawer's open state
- size="large" — to match the drawer close-button size
See the CloseButton documentation for its full API.
DrawerPanelBody
The DrawerPanelBody component is a container for the main content of the DrawerPanel.
By default it has no inner spacing. Set the hasSpacing prop to apply inner spacing consistent with DrawerPanelHeader, so you don't have to add it yourself.
<DrawerPanelBody hasSpacing>{/* Drawer content goes here */}</DrawerPanelBody>
👉 For examples with Navigation content inside DrawerPanelBody, see the Header component.
API
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
| children | ReactNode | — | ✕ | Children node |
| hasSpacing | bool | false | ✕ | Whether the content has inner spacing matching the header |
On top of the API options, the components accept additional attributes. If you need more control over the styling of a component, you can use style props and escape hatches.
Accessibility
Always provide an accessible name for the Drawer using aria-label so screen readers can announce what the dialog contains:
<Drawer id="drawer-example" isOpen={isOpen} onClose={handleClose} aria-label="Navigation">
{/* … */}
</Drawer>
ℹ️ DrawerPanelHeader renders as a <header> element. When nested inside a <dialog>, <header> does not carry the banner landmark role (per HTML-AAM), so there is no landmark pollution.
ℹ️ The animation effect of this component is dependent on the prefers-reduced-motion media query.
Full Example
import React, { useState } from 'react';
import {
Button,
CloseButton,
Drawer,
DrawerPanel,
DrawerPanelHeader,
DrawerPanelBody,
} from '@alma-oss/spirit-web-react';
export const Example = () => {
const [isOpen, setIsOpen] = useState(false);
const handleOpen = () => setIsOpen(true);
const handleClose = () => setIsOpen(false);
return (
<>
<Button onClick={handleOpen} aria-controls="drawer-example">
Open Drawer
</Button>
<Drawer id="drawer-example" isOpen={isOpen} onClose={handleClose} aria-label="Drawer">
<DrawerPanel>
<DrawerPanelHeader>
<CloseButton size="large" aria-expanded={isOpen} aria-controls="drawer-example" onClick={handleClose} />
</DrawerPanelHeader>
<DrawerPanelBody hasSpacing>Drawer content</DrawerPanelBody>
</DrawerPanel>
</Drawer>
</>
);
};