Panel
The dense surface for toolbars, sidebars and nested regions.
@luc/uiExamples
Surface tones
Panel is the dense surface under everything else — a toolbar, a sidebar, a code block, a region inside a card. The tone says where it sits in the stack, not how important it is.
default
sunken
raised
<Panel tone="default">…</Panel>
<Panel tone="sunken">…</Panel>
<Panel tone="raised">…</Panel>Header, body and actions
`PanelHeader` is the region's title bar: a minimum height, a hairline under it and a right-hand slot, which is what keeps a toolbar's controls in the same place on every panel in a product.
Constituents
61AAPL
4.1%
MSFT
3.8%
NVDA
3.2%
<Panel>
<PanelHeader actions={<Button size="sm" variant="ghost">Refresh</Button>}>
<Text variant="label">Constituents</Text>
<Badge tone="neutral" size="sm">61</Badge>
</PanelHeader>
<PanelBody>…</PanelBody>
</Panel>Panel or Card
The distinction, shown with the same content: a Card is the surface a reader acts on, a Panel is a region inside one. A Panel never carries elevation, so a page cannot end up with two competing shadows.
Card
A surface with elevation
Panel inside a Card
Panel
A region, no elevation of its own
<Card>
<CardHeader>
<CardTitle>Card</CardTitle>
<CardDescription>A surface with elevation</CardDescription>
</CardHeader>
<CardContent>
<Panel tone="sunken">…</Panel>
</CardContent>
</Card>Nested regions
A panel inside a panel separates two kinds of region with one hairline instead of a second border, a margin and a background — which is what keeps a dense tool screen legible.
Workspace
Nested region
Nested region
<Panel>
<PanelHeader>…</PanelHeader>
<PanelBody>
<Panel tone="sunken">…</Panel>
</PanelBody>
</Panel>Bordered and borderless
`bordered={false}` is for a panel that already sits inside a framed surface: the frame is drawn once, by the outer region, and the inner one keeps only its background.
bordered
bordered=false
<Panel tone="sunken">…</Panel>
<Panel tone="sunken" bordered={false}>…</Panel>Usage
import { Panel, PanelBody, PanelHeader } from "@luc/ui";<Panel>
<PanelHeader>
<Text variant="label">Constituents</Text>
</PanelHeader>
<PanelBody>…</PanelBody>
</Panel>`tone` says where the panel sits in the stack, not how important it is; `bordered` drops the frame when the surface outside it already has one.
Package setup — peer requirements, the stylesheet and the provider — is on installation.
API
Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.
| Export | Kind | Signature |
|---|---|---|
Panel | 2 documented props | ({ className, tone, bordered, ...props }: PanelProps) => import("@types/react").JSX.Element |
PanelBody | export | ({ className, ...props }: React.ComponentPropsWithRef<"div">) => import("@types/react").JSX.Element |
PanelHeader | 1 documented props | ({ className, actions, children, ...props }: PanelHeaderProps) => import("@types/react").JSX.Element |
Panel props
Type: PanelProps
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
bordered? | boolean | undefined | — | Hairline frame. Default `true`. |
tone? | "default" | "raised" | "sunken" | undefined | — | `sunken` sits inside cards; `default` sits on the canvas. |
PanelHeader props
Type: PanelHeaderProps
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
actions? | ReactNode | — |
Guidelines
Do
- Use `Panel` for the regions *inside* a page or a card: a toolbar, a sidebar, a code block, a section of an inspector.
- Pick `tone="sunken"` when the panel sits on a raised surface and `tone="raised"` when it has to read as a layer inside a dense tool screen.
- Use the `PanelHeader` action slot rather than a row of buttons above the panel — a toolbar belongs on the region it acts on.
Don't
- Do not stack two surfaces with the same tone: two identical panels side by side read as one broken surface.
- Do not add elevation to a Panel by class; elevation belongs to `Card`, and a page with both has two shadows competing.
- Do not nest a panel inside a panel without changing the tone — the hairline between them is what makes the nesting legible.
Accessibility
A panel is a `div`: a surface, not a landmark. When it is a page's toolbar it needs a name (`aria-label`) or an enclosing `Toolbar`, and when it groups controls it should be a `fieldset` or carry `role="group"` — the component adds neither, because only the caller knows which region it is.
Family
Layout
Space, rhythm and the surfaces a page is made of.
10 documented entries in this family. Open the family index
Related