Components

Panel

Panel is a persistent side rail used to display supplemental content alongside the main interface.

Panel presents supplemental content or actions in a side rail that sits alongside the main interface and pushes it aside, rather than overlaying it like a Drawer. Below the mobile breakpoint it switches to a bottom-sheet overlay.

Panel is composed from Panel.Header, Panel.Footer, and Panel.CloseButton, and its open/closed state is coordinated through PanelProvider — read it anywhere beneath the provider with usePanelContext. Children are automatically wrapped in a scrollable content region, so you don't need to wrap them yourself.

import { Panel,PanelProvider } from '@sproutsocial/racine'
() => {
const Toggle = () => {
const { togglePanel } = usePanelContext()
return (
<Button appearance='primary' onClick={togglePanel}>
Toggle panel
</Button>
)
}
return (
<PanelProvider defaultOpen>
<Box display='flex' height='400px' width='100%' bg='neutral.0' borderRadius={300} overflow='hidden' boxShadow='low'>
<Box flex='1 1 auto' p={400} overflow='auto'>
<Text.Headline as='h2'>Main content</Text.Headline>
<Text.BodyCopy as='p' mt={300}>
The panel renders inline at desktop widths and pushes this content aside.
</Text.BodyCopy>
<Box mt={400}>
<Toggle />
</Box>
</Box>
<Panel
title='Panel title'
titleId='panel-title'
aria-labelledby='panel-title'
closeButtonLabel='Close panel'
>
<Text.BodyCopy as='p'>
Supplemental content lives here, alongside the main interface.
</Text.BodyCopy>
</Panel>
</Box>
</PanelProvider>
)
}

Use the direction prop to anchor the panel to the left instead of the default right, and width to override its default size.

Properties

NameTypeDefaultDescriptionRequired?
children
React.ReactNode
closeButtonLabel
string
Label for the close button. Usually "Close".
header
React.ReactNode
Custom header content. When provided, replaces the auto-rendered default header entirely — `title` and `titleId` are ignored.
footer
React.ReactNode
Custom footer content. Not rendered when omitted.
headerless
boolean
Renders children flush, without the built-in header/close button or content padding, and lets the children own overflow scrolling. Use when the content provides its own chrome (e.g. an embedded agent UI). Provide `aria-label` (or `aria-labelledby`) for an accessible name, since no header title is rendered. `title`, `titleId`, and `closeButtonLabel` are ignored in this mode. Defaults to false.
title
string
Title shown in the auto-rendered default header. Ignored when `header` is provided.
titleId
string
Sets the `id` on the title element of the auto-rendered header. When the default header is used, Panel automatically wires `aria-labelledby` to this id so the dialog/aside has an accessible name. Pass an explicit `aria-labelledby` to override (e.g. when pointing at a different element). Ignored when `header` is provided — supply your own `aria-labelledby` in that case.
direction
"left"
"right"
"bottom"
Side the panel anchors to on desktop. Defaults to "right".
width
number
Width (px) when direction is "left" or "right", or height (px) when direction is "bottom". Defaults to 384 to match the existing web-app-core Panel.
gap
number
Visual gap (px) between the panel and the adjacent content. Applied as margin on the side facing the content (left when direction="right", right when direction="left", top when direction="bottom"). Animates with the panel's open/close transition and collapses to 0 when closed so the gap does not remain visible alongside a zero-width panel. Defaults to 0.
mobileBreakpoint
number
string
Forwarded to `useIsMobile`. Accepts a px number or any CSS media-query length. Below this width, the panel renders as an overlay bottom sheet (via seeds-react-drawer). Defaults to the theme's `breakpoints.sm`.
zIndex
number
Applies only to the mobile bottom-sheet rendering.
id
string
Optional id used for data-qa-panel attributes.
snapPoints
TypeDrawerSnapPoint[]
Snap points the panel can rest at when rendered as a mobile bottom sheet. 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. Ignored on the desktop side-panel rendering.
defaultSnapPoint
TypeDrawerSnapPoint
null
Initial snap point for uncontrolled use. Mobile only.
snapPoint
TypeDrawerSnapPoint
null
Controlled active snap point. Pair with `onSnapPointChange`. Mobile only.
onSnapPointChange
(snapPoint: TypeDrawerSnapPoint | null) => void
Fires when the active snap point changes. Mobile only.
snapToSequentialPoints
boolean
When true, fast swipes can't skip past adjacent snap points. Mobile only.
actions
TypeDrawerActionProps[]
Action buttons shown in a floating rail above the panel on mobile (the bottom-sheet rendering). Ignored on desktop side-panel rendering — pass actions through `header`/`footer` slots there. The rail owns the close button so the default header omits its built-in close affordance.
actionsInHeader
boolean
Opt out of the floating mobile rail and render the `actions` inline in the header as pill buttons instead. Useful for nested bottom sheets and snap-point layouts where the floating rail would collide with surrounding UI. Defaults to `false`. When `header` is omitted, Panel auto-composes a mobile header that renders the title, the `actions` as pills, and a close-button pill. When `header` is provided, the consumer is responsible for rendering the actions inside their own header — `actions` is forwarded for context only.