Inspector
An editor's screen parts: the header bar, the stage it works on and the inspector of settings beside it.
The inspector pattern is the set of parts an editor is made of: a HeaderBar, the Stage the work sits on, and the Inspector of settings beside it. Put them in AppShell and an editor works from a 390px phone, where the inspector becomes a sheet, to a wide desktop.
How the parts fit
The header
HeaderBarholds the app's mark, the document's title and its actions. The title truncates when space runs out, and the actions fold into a "More" menu when they don't fit.The stage
Stagefits the artwork at its shape into the space it has. Artwork may overlap the canvas's edges, which clip it, and a crop mode puts handles on its frame to resize it.The inspector
Inspectoris a panel of titled sections, each anInspector.Section, holding rows of controls. A section can offer Reset for its own settings.Its rows
Each
Inspector.Rowis 50px tall, with the label at the start and the control at the end. A slider labels itself with its value badge.
HeaderBar
When to use it
Use it for
- The top of an app window or editor: the document's name and the actions that apply to it
Not for
- A marketing site's navigation: use NavBar
- Actions for one mode: use FloatingToolbar
Examples
Document header
An editor's header over its canvas: Rename opens a form dialog, and Undo and Redo, after a separator, walk back through the names.
Spring launch
Settings header
A plain header for a settings window: the title, and one action that stays focusable once it's done.
Two settings changed
Variants and states
Editor header
The mark and title, text and icon actions, the canvas shape select, then undo, redo and help after a separator.
When it narrows
At 400px the lowest-priority actions fold into the More menu; the title keeps its words.
Props
HeaderBar
| Prop | Type | Default | Description |
|---|---|---|---|
titlerequired | ReactNode | What's open, such as the document's name. It truncates when space runs out. | |
mark | ReactNode | The app's own icon, 24px, before the title. | |
dragRegion | boolean | In the desktop app, lets the window be dragged from anywhere in the bar (its buttons still take presses) and leaves room for the window controls. | |
children | ReactNode | The actions, at the end: HeaderBar.Actions, HeaderBar.Separator and icon buttons. |
It also takes Omit<ComponentPropsWithRef<"header">, "title">.
HeaderBar.Action
| Prop | Type | Default | Description |
|---|---|---|---|
labelrequired | string | What it does, such as "Crop". The bar shows it as text unless iconOnly; the menu always does. | |
onSelectrequired | () => void | Runs the action, from the bar or from the "…" menu. | |
icon | ComponentType<IconComponentProps> | An icon for it, shown in the menu and, with iconOnly, in the bar. | |
iconOnly | boolean | Shows only the icon in the bar, with the label as its tooltip and name. Needs icon. | |
disabled | boolean | Keeps it from being chosen. The bar's button stays focusable (aria-disabled), so pressing the last
Undo or Delete doesn't drop keyboard focus. | |
priority | number | 0 | Higher stays in the bar longer. Defaults to 0. |
HeaderBar.Actions
| Prop | Type | Default | Description |
|---|---|---|---|
moreLabel | string | "More" | Accessible name of the "More" button. Defaults to "More". |
size | "sm" | "control" | "button" | Height of the "More" button, to match the items: "sm" (28), "control" (34) or "button" (36, the
default). Compact density shortens them like any control. | |
menu | ReactNode | Your own items for the "More" menu, which then always shows, such as every choice with actions on them. Without it, the menu lists the items that don't fit and shows only when something doesn't. | |
gap | SpaceValue | Space between children. |
It also takes ComponentPropsWithRef<"div">.
Also exported
| Export | Description |
|---|---|
HeaderBarSeparator(): ReactElement | A 1px × 24 line between groups of actions. |
Accessibility
A header holding a title and buttons. Actions that don't fit move into a "More actions" menu (a menu button), never off screen; icon-only actions are named by their labels, with tooltips. With dragRegion the desktop window drags from the bar while its buttons keep taking presses.
| Keys | What they do |
|---|---|
| Enter or Space | Presses the focused action, or opens More actions with the actions that don't fit |
| Arrow keys | Move through More actions while it's open, where Enter chooses an action |
| Escape | Closes More actions and puts focus back on its button |
Motion
It doesn't move.
With reduced motion: Nothing changes.
Layout
It takes its container's width at 56px tall (--bt-h-header), padded 16px a side, or past the window controls at the start with dragRegion in the desktop app. The 24px mark and the actions keep their size and never wrap: as the bar narrows the lowest-priority actions fold into More actions first, and only then does the title truncate, with its full text in its title.
Related
See it in the Deckhand demo.
Inspector
When to use it
Use it for
- The settings beside a canvas or a preview: an editor's right-hand panel
- Any long list of controls grouped into sections that reset to defaults
Not for
- A form that's submitted: use the form fields with a submit button
- A few controls in a toolbar: use HeaderBar or FloatingToolbar
Examples
Export settings
A small inspector: one section of rows that resets to its defaults, and a footer with the main action.
Image
Nothing exported yet
Placement row
A slide editor's placement section: a split row with a tilt pad and the chip that lays the picture flat, beside an anchor grid.
Tilted, anchored to the center
Placement
Variants and states
Slide settings
Sections on nested surfaces, rows of controls, a split row for the tilt pad and the anchor grid, and a footer that stays put while the sections scroll.
Picture
Placement
Background
Props
Inspector
| Prop | Type | Default | Description |
|---|---|---|---|
labelrequired | string | Names the panel for screen readers, such as "Slide settings". | |
footer | ReactNode | What stays at the bottom while the sections scroll, such as <Inspector.Footer> with Copy and Export. |
It also takes ComponentPropsWithRef<"div">.
Inspector.Footer
It also takes ComponentPropsWithRef<"div">.
Inspector.Row
| Prop | Type | Default | Description |
|---|---|---|---|
label | ReactNode | What the row sets, shown at its start. Leave it out when the control brings its own, as Slider does. | |
extra | ReactNode | Something beside the label, such as a Chip that resets this row. | |
block | boolean | Lets the row grow to fit what it holds, such as a swatch grid, padded 16 on every side. | |
children | ReactNode | The control. Without a label, it fills the row. |
It also takes Omit<ComponentPropsWithRef<"div">, "children">.
Inspector.RowSplit
It also takes ComponentPropsWithRef<"div">.
Inspector.Section
| Prop | Type | Default | Description |
|---|---|---|---|
titlerequired | string | The section's heading, such as "Background". | |
onReset | (() => void) | Puts back the section's defaults. Given, the header shows a Reset action. | |
resettable | boolean | true | Whether anything in it differs from its defaults; while it doesn't, Reset is dimmed. Defaults to true. |
resetLabel | string | "Reset" | The Reset action's word. Defaults to "Reset"; it's read with the title, as in "Reset Background". |
It also takes Omit<ComponentPropsWithRef<"section">, "title">.
Accessibility
A named region; each section is a region named by its heading (an h2). Reset in a header is named with the section ("Reset Background") and stays focusable while dimmed. The sections scroll inside the panel, so the footer's actions are always in reach.
| Keys | What they do |
|---|---|
| Enter or Space | Presses a section's Reset, which puts its rows back to their defaults; dimmed, it keeps focus and does nothing |
Motion
It scales to 97% while it's pressed, over `--bt-dur-press`, and springs back when it's let go.
With reduced motion: A section's Reset button still shrinks to 97% while it's pressed, but at once instead of easing.
Layout
It's 340px wide (--bt-w-inspector), never wider than its container, and as tall as its container lets it be: the sections scroll inside with faded edges while the footer stays at the bottom. Rows are 50px tall (--bt-h-row), split rows 64px (--bt-h-row-split) and block rows grow to fit; row labels and section titles truncate with their full text in their title, and each section's Reset is 28px tall.
Related
See it in the Deckhand demo.
Stage
When to use it
Use it for
- The preview in an editor: a slide, a picture, a page
- Anything shown at a fixed shape that has to fit whatever room it gets
Not for
- Content that scrolls: use a page layout
- A thumbnail in a grid: use FitBox
Examples
Canvas shapes
The canvas at each shape it's given: pick one and it reshapes, staying centered in its space.
Crop canvas
A canvas in crop mode, its size kept in state while the handles move.
Slide editor
A slide editor's preview: a title field and background swatches, an inspector's width, change what the canvas shows.
Spring launch
Background · Lilac
Slide preview
A slide preview at its output size, with the canvas exposed for a toolbar to anchor to.
Spring launch
Variants and states
Canvas and crop
Change the shape and the canvas reshapes on spring.smooth; Resize fades the background and shows the handles and the toolbar.
Quarterly review
Props
Stage
| Prop | Type | Default | Description |
|---|---|---|---|
labelrequired | string | Names the canvas for screen readers, such as "Slide preview". | |
sizerequired | StageSize | The canvas size in output pixels; the canvas shows at this shape, as large as fits. | |
background | string | The canvas's CSS background: a color, a gradient or an image. It fades out in crop mode. | |
cropping | boolean | Crop mode: the background fades, and handles on the canvas's frame resize it. | |
onSizeChange | ((size: StageSize) => void) | Called while a crop handle is dragged, with the new size. | |
onSizeCommit | ((size: StageSize) => void) | Called when a crop drag ends, with the size it settled on, for one undo step per drag. | |
minSize | number | 64 | The smallest side a crop can leave, in output pixels. Defaults to 64. |
canvasRef | Ref<HTMLDivElement> | The canvas element, to anchor a FloatingToolbar under it. | |
children | ReactNode | What's drawn on the canvas. It may overlap the canvas's edges, which clip it. |
It also takes Omit<ComponentPropsWithRef<"div">, "children">.
StageSize
A canvas size in output pixels, such as 1600 × 900.
| Field | Type | Default | Description |
|---|---|---|---|
widthrequired | number | Width in output pixels. | |
heightrequired | number | Height in output pixels. |
Also exported
| Export | Description |
|---|---|
useStageLayout(dependency?: string | number | boolean): StageLayout | Keeps a Motion element on a Stage canvas in shape while the canvas reshapes. The canvas reshapes with a
layout animation, which stretches what's on it; spread this on the element and it measures with the
canvas and scales evenly from its old box to its new one instead. Pass what else moves it, such as its
anchor, as dependency. With reduced motion, it turns the animation off as the canvas does. |
Accessibility
The canvas is an image named by label; what it shows is set from the controls around it. The crop handles take the pointer; the keyboard sets the same size through exact fields, such as width and height in a canvas Select's footer.
It takes no keyboard input of its own.
Motion
It changes shape as one surface, on `spring.smooth`, or `spring.morph` for a big change, rather than closing and reopening.
With reduced motion: The canvas takes its new shape at once, and in crop mode its background goes and its handles show without fading.
Layout
It fills its parent's box, so give the parent a height, and draws the largest canvas of its shape that fits 32px inside it, centered, r12 with a card shadow; artwork may overlap the canvas's edges, which clip it. In crop mode the eight 12px handles each have a 24px hit area.
Related
See it in the Deckhand demo.