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><Paneltitle='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
| Name | Type | Default | Description | Required? |
|---|---|---|---|---|
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. |