Components

Drawer

Drawer is used to overlay content on top of the interface. They are intended to capture the user's attention in order to inform or shift focus to a pertinent task.

import { Drawer } from '@sproutsocial/racine'
() => {
const [open, setOpen] = useState(false)
const toggleDrawer = () => setOpen(!open)
return (
<Box>
<Button appearance='secondary' onClick={toggleDrawer} width={1}>
Open drawer
</Button>
<Drawer
isOpen={open}
onClose={toggleDrawer}
closeButtonLabel='Close this drawer'
id='right-drawer'
zIndex={900}
>
<Drawer.Header title='Drawer Header' />
<Drawer.Content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</Drawer.Content>
</Drawer>
</Box>
)
}

Properties

NameTypeDefaultDescriptionRequired?
children
React.ReactNode
closeButtonLabel
string
Label for the close button. Usually this should be "Close"
direction
"left"
"right"
"bottom"
"right"
Whether the drawer slides in from the left or right side of the screen
disableCloseOnClickOutside
boolean
false
In some cases, you may not want the user to be able to click outside of the drawer to close it. You can disable that with this prop.
modal
boolean
false
When true, siblings are inerted while the drawer is open — appropriate for forms or settings panels where page interaction should be blocked. Defaults to false to preserve the original non-modal behavior where the rest of the page remains interactive (side info panels, notification slide-outs, persistent inspectors, etc.).
id
string
Optional id used for data-qa-drawer attributes
open
boolean
offset
number
0
onClose
() => void
zIndex
number
7
width
number
600
snapPoints
TypeDrawerSnapPoint[]
Snap points the drawer can rest at when swiped. Only applied to bottom drawers. Numbers 0–1 are viewport-height fractions; numbers > 1 are pixels; strings accept `px`/`rem` (e.g. `"480px"`, `"30rem"`). Order matters — the last entry is the "expanded" state and gets a `data-expanded` attribute on the popup.
defaultSnapPoint
number | string
null
Initial snap point for uncontrolled use.
snapPoint
number | string
null
Controlled active snap point. Pair with `onSnapPointChange`.
onSnapPointChange
(snapPoint: TypeDrawerSnapPoint | null) => void
Fires when the active snap point changes (drag release, programmatic update, etc.).
snapToSequentialPoints
boolean
When true, fast swipes can't skip past adjacent snap points — drag distance alone determines the next stop. Defaults to base-ui's `false` (velocity-based skipping).
actions
TypeDrawerActionProps[]
Action buttons shown in a floating rail above the drawer on mobile (the bottom-sheet rendering). The rail also owns the close button — when this prop is provided, the default `Drawer.Header` omits its built-in close button so the rail can render it instead. Ignored on desktop side drawers.
actionsInHeader
boolean
false
Opt out of the floating rail and keep the actions inside `Drawer.Header` (the pre-rail behavior). Useful for nested bottom sheets and snap-point drawers where the rail-above placement would collide with surrounding UI or fall off-screen at the highest snap point. Defaults to `false`. When `true`, the Drawer does NOT render the rail; consumers are responsible for rendering action buttons (and the close button) inside their `Drawer.Header`.

Subcomponents

Drawer Header

Most drawers should have headers. The Drawer.Header subcomponent makes it easy to build a default header — simply supply a title prop and the Drawer Header will automatically render the title along with a close button.

If you need to build a custom header, you can do so by passing a children prop, which allows a developer to completely customize the header while maintaining the correct padding. You can use the Drawer.CloseButton subcomponent to render the close button manually.

Finally, a render prop can be supplied, which gives the developer full control of how the header will render. The function receives the context of the parent Drawer as an argument.

Basic Drawer Header
<Drawer.Header title='Notifications' />
Drawer Header with children
<Drawer.Header>
<Tabs selectedId='1' onSelect={() => {}}>
<Tabs.Button id='1'>
<Box display='flex' alignItems='center'>
<Icon name='bell-outline' mr={350} aria-hidden />
<Text as='div' fontSize={200} fontWeight='semibold'>
Notifications
</Text>
</Box>
</Tabs.Button>
<Tabs.Button id='2'>
<Box display='flex' alignItems='center'>
<Icon name='triangle-exclamation-outline' mr={350} aria-hidden />
<Text as='div' fontSize={200} fontWeight='semibold'>
Issues
</Text>
</Box>
</Tabs.Button>
</Tabs>
<Drawer.CloseButton />
</Drawer.Header>
Drawer Header with render
<Drawer.Header render={({ onClose, closeButtonLabel }) => (
<Box bg='red.0' width={1} p={500} display='flex' alignItems='center' justifyContent='space-between'>
<Text>Custom Drawer Header</Text>
<Button onClick={onClose} aria-label={closeButtonLabel}>
Custom close button
</Button>
</Box>
)} />

Drawer Close Button

When making a custom header, a close icon button is still needed. The Drawer.CloseButton subcomponent makes it simple to include the standard close icon button in any drawer. The base component of Drawer.CloseButton is a standard Button and accepts the same props as that component.

The close button also accepts a children if you would like to render something other than the icon.

If you need custom on-close behavior or more flexibility in rendering, there is a render prop which receives the context of the parent Drawer as an argument.

Basic Close Button
<Drawer.CloseButton />
Drawer Close Button with children
<Drawer.CloseButton appearance='primary' aria-label="Close Drawer Example Button">
<Icon name='bell-outline' aria-hidden />
</Drawer.CloseButton>
Drawer Close Button with render
<Drawer.CloseButton render={({onClose, closeButtonLabel}) => (
<Button onClick={onClose} aria-label={closeButtonLabel}>
Custom close button
</Button>
)} />

Recipes

Drawer with empty header

() => {
const [open, setOpen] = useState(false)
const toggleDrawer = () => setOpen(!open)
return (
<Box>
<Button appearance='secondary' onClick={toggleDrawer} width={1}>
Open drawer
</Button>
<Drawer
isOpen={open}
onClose={() => setOpen(false)}
closeButtonLabel='Close this drawer'
id='no-header-drawer'
zIndex={900}
>
<Drawer.Header />
<Drawer.Content>
<Box display='flex' alignItems='center' flexDirection='column'>
<Box width='400px' height='400px' bg='neutral.200' />
<h3>Some headline</h3>
<Text fontSize={400} textAlign='center' px={500}>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</Text>
</Box>
</Drawer.Content>
</Drawer>
</Box>
)
}

Drawer sliding in from left

By default, the drawer component will slide in from the right side of the screen. Set the direction prop to left to change this behavior.

import { Drawer } from '@sproutsocial/racine'
() => {
const [open, setOpen] = useState(false)
const toggleDrawer = () => setOpen(!open)
return (
<Box>
<Button appearance='secondary' onClick={toggleDrawer} width={1}>
Open drawer
</Button>
<Drawer
isOpen={open}
onClose={toggleDrawer}
closeButtonLabel='Close this drawer'
id='left-drawer'
direction='left'
zIndex={900}
>
<Drawer.Header
title='Drawer Header'
/>
<Drawer.Content>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
</Drawer.Content>
</Drawer>
</Box>
)
}