Panel

A widget or an overlay: a grey outer with a quiet frame line, the header on the grey, the content in a white bordered body, the footer back on the grey.

Examples

A list panel

Needs a look
3
Refund over $500

Waiting on Ana

Waiting on you
Weekly eval

312 of 400 cases

Running
triage agent

Replies 1.9 s slower than usual

Slow

A chart panel

Conversations
Last 24 hours

Conversations per two hours, last 24 hours
DateResolved
00:0022
02:0018
04:0014
06:0012
08:0011
10:0015
12:0024
14:0041
16:0063
18:0078
20:0086
22:0091

A decision with its buttons in the footer

Prompt release v14
Paused at 25%
Eval score
94.1, was 95.3
Refund errors
0.4%

States

  • Needs a look
    3
    Refund over $500

    Waiting on Ana

    Waiting on you
    Weekly eval

    312 of 400 cases

    Running
    triage agent

    Replies 1.9 s slower than usual

    Slow

    rest

Usage

When to use it
Use
An overview widget shows a few numbers or a short list, about 8 rows at most: what needs a look, the last releases, API keys.
Use
A chart widget: one chart with a title and a range, such as conversations over the last day (Chart frame="panel" is this anatomy).
Use
A card that asks the person for a decision, such as a prompt release waiting on Resume or Roll back, with the buttons in the footer.
Use
A short read-only fact set, such as an environment and its workspace ID.
Not for
A working surface: a big table or stream, a trace, a log, code, a form or the detail of one object; anything that scrolls, filters, streams or has fields the person edits, such as a settings group. Use Card.
Not for
A task or a question that must finish first. Use Dialog.

Rules

6 rules
Must
Use a Panel for a summary or a decision: a short list, one chart, a read-only fact set or a card that asks for a choice, with a title, a meta and at most one action. Fields the person edits belong in a Card. Because the grey outer gives a widget a ground of its own and puts its buttons on the grey, but a long list or a working surface needs the white Card's edge and header rule to read as one place.
Never
Scroll inside a Panel; link to a full page for more. Because a white body that scrolls in a grey outer hides its edge, so no one can tell the list goes on.
Never
A widget is a Panel and a working surface is a Card; never a Card inside a Panel or a Panel inside a Card. Because a white card in a grey panel is a box in a box; side by side, the grey widget and the white table tell the person which one to glance at and which one to work in.
Must
Split rows in a PanelBody with rule-row and pad them px-3; an Item does both itself. Because the body sits 4px inside the panel, so px-3 lands the text on the same 16px as the header.
Should
Give the header at most one action, in PanelAction, and put "View all" there or in the footer. Because a header with several controls turns a glanceable widget into a toolbar and crowds the title off a narrow panel.
Must
Put a quiet line or buttons that belong to the whole panel in PanelFooter, never inside PanelBody. Because the body is the one white group of rows, and a footer line inside it reads as one more row.

Accessibility

2 checks
Panel renders a section; give it aria-label, or name it with aria-labelledby on its PanelTitle.
A list inside takes role="list" with listitem rows, named like the panel.

Edge cases

5 edge cases
Very long title
Truncates to one line and keeps the meta and the action.
More than about 8 rows
Show the first rows and a View all button in the header or footer.
Empty body
Put an empty state in the body; the panel keeps its header.
Right to left
The title and meta move to the right and the action to the left.
Forced colors
The panel keeps an outline and the body its frame border.

API

5 props
Panel
section
PanelHeader
div
PanelAction
div
PanelBody
div
PanelFooter
div

Tokens

7 tokens
--surface-frame
color-mix(in oklch, var(--surface-card) 55%, var(--paper))
--surface-page
var(--paper)
--line-frame
oklch(var(--ink-c) / var(--line-frame-alpha))
--line-row
oklch(var(--ink-c) / 0.08)
--radius-frame
10px
--text-3
oklch(var(--ink-c) / 0.66)
--type-label
400 14px/16px var(--font-sans)

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.