suiss/ui · Pattern
Panel
A side panel that renders as a Sheet on desktop and a swipeable Drawer on mobile.
Panel is an open-source pattern from suiss/ui for React. The @esuiss/ui CLI copies its source into your project, so you own the code.
Panel presents secondary content such as forms, filters or details without leaving the page. On desktop it renders a suiss/ui Sheet that slides in from the chosen side. On mobile (below 48rem, via useIsMobile) it switches to a Drawer with a swipe handle, and every subcomponent swaps to its Drawer counterpart.
The parts mirror the Sheet and Drawer anatomy: a trigger, content with an optional close button, header, title, description, body, footer and a close control. Use it where a desktop layout calls for a side sheet and a phone calls for a bottom sheet.
Installation
CLI
Works in any project with a components.json. See Installation for the one-line registry setup. Or use the suiss/ui CLI:
Manual
-
Add the
cnhelper. -
Copy the source into
components/patterns/panel.tsx:
- Update the import paths to match your project.
Usage
- Compose
PanelTriggerandPanelContentinsidePanel. All parts must be used insidePanel, or they throw. - Put scrollable or form content in
PanelBody, which applies padding that matches each presentation.
- Open state is uncontrolled by default; use
defaultOpenfor an initial state, oropenwithonOpenChangeto control it. - Use the
renderprop onPanelTriggerandPanelCloseto render them as a suiss/uiButton.
- Open state is uncontrolled by default; use
defaultOpenfor an initial state, oropenwithonOpenChangeto control it. - Set
asChildonPanelTriggerandPanelCloseto render a suiss/uiButtonin their place.
Examples
By default
Starts open with defaultOpen and closes from the close button.
Sides
Opens the desktop sheet from the top, right, bottom and left.
With close label
Replaces the close icon with a Done text button through closeLabel.
Without close button
Hides the built-in close button and closes from a Cancel button instead.
Floating
Insets the mobile drawer from the screen edges with floating.
API Reference
Panel
The root that chooses Sheet or Drawer and holds the open state.
| Prop | Type | Default | Description |
|---|---|---|---|
onOpenChange | (open: boolean) => void | - | Called with the new open state when the panel opens or closes. |
floating | boolean | - | Insets the mobile drawer from the screen edges. Has no effect on desktop. |
Also accepts the props of React.ComponentProps<typeof Sheet>.
PanelTrigger
The button that opens the panel.
| Prop | Type | Default | Description |
|---|---|---|---|
render | React.ReactElement | - | Replaces the rendered element, for example with a Button. |
Also accepts the props of React.ButtonHTMLAttributes<HTMLButtonElement>.
PanelContent
The popup surface, with an optional close button.
| Prop | Type | Default | Description |
|---|---|---|---|
side | "top" | "right" | "bottom" | "left" | "right" | The screen edge the desktop sheet slides in from. Ignored on mobile. |
showCloseButton | boolean | true | Shows the built-in close button. |
closeLabel | string | - | Text for the close button in place of the icon. |
Also accepts the props of React.HTMLAttributes<HTMLElement>.
PanelHeader
Groups the title and description.
Also accepts the props of React.ComponentProps<"div">.
PanelTitle
The panel's heading, which names the dialog.
Also accepts the props of React.HTMLAttributes<HTMLHeadingElement>.
PanelDescription
Supporting text that describes the dialog.
Also accepts the props of React.HTMLAttributes<HTMLParagraphElement>.
PanelBody
The padded main content area.
Also accepts the props of React.ComponentProps<"div">.
PanelFooter
Holds the panel's actions.
Also accepts the props of React.ComponentProps<"div">.
PanelClose
A button that closes the panel.
| Prop | Type | Default | Description |
|---|---|---|---|
render | React.ReactElement | - | Replaces the rendered element, for example with a Button. |
Also accepts the props of React.ButtonHTMLAttributes<HTMLButtonElement>.
Accessibility
- The content is a
dialognamed byPanelTitleand described byPanelDescription. - Escape closes the panel and returns focus to the trigger.
- The built-in close button is named Close, or by
closeLabelwhen set.
Notes
Styling hooks: data-slot="panel", panel-trigger, panel-content, panel-header, panel-title, panel-description, panel-body, panel-footer and panel-close. The presentation follows the viewport at render time, so a panel open while the viewport crosses 48rem re-renders in the other presentation.