Nirvana enforces most of the design: an applet cannot pass a color or a size. What is left to the author is what to put on a screen and how to word it, and that is what this page is about.
Four ideas, in order
When a decision is unclear, go back to these.
- Air. Space does the work that lines and boxes do elsewhere. Few elements per view, generous margins, one thing per row. If a screen feels busy, remove something before restyling anything.
- Glass. Surfaces that float over the desktop (the dock, the launcher, a window’s sidebar) are translucent, and the compositor blurs what is behind them. Glass says “this sits above your work”.
- Soft shapes. Nothing has a sharp corner. Controls are capsules, groups and panels have large radii, and things move with a little spring.
- Quiet color. There is no accent hue. Emphasis comes from contrast and weight: the primary button is simply the darkest thing on the surface (the lightest, in dark appearance). Color is left to content, and to the rare status that must not be missed.
Light and dark are equals. Every color is a token with both values, so an applet is right in both without doing anything.
Using components
- One primary button per view. In a sheet the actions share the width, with the primary one on the right. A destructive action is never primary.
- Rows do the obvious thing. A row with an id is clickable as a whole. Secondary actions go in the trailing slot: a small button, or the round info button that opens a sheet.
- Direct manipulation. A toggle applies at once; there is no “Apply”. A control shows the real state of the system and snaps back if a change fails.
- Status belongs in the subtitle (“Connected”), progress in the spinner accessory. Badges are not for passing states.
- A sheet asks one question or shows one object. Give it an id, so that Escape and a click outside dismiss it. Put the caret in its first field.
- Errors say what failed and what to do next, in a
Banneror in red callout text inside the sheet that caused them. Never raw tool output. - Text on glass is primary or secondary only, never tertiary: it has to hold up over any wallpaper.
- Do not stack glass on glass, and do not put glass inside a content pane.
Choosing the shell
| The applet is | Use |
|---|---|
| One screen of settings, or one list | Page |
| Several screens to move between | SplitView with SidebarItems and one Page |
| A tool with a toolbar and a working area | Pane |
| A few steps, one question at a time | Wizard |
Nothing jumps
Motion is how the interface says what just happened. A change the person causes is never a cut. Nirvana animates what it can see changing, and an applet helps it see:
- Give list items keys. A keyed row that moves slides; an unkeyed one is redrawn in place.
- Change one thing per event. If a click opens a sheet, do not also reorder the list under it.
- Never stand something in for what is loading, to swap it a moment
later. Show the group with
loading(true); let the content arrive whole. - Design every path, not the first one. For anything that can be opened,
dragged or toggled, walk through: the empty state, the first item, many
items, taking it back out, doing it fast. Each is a state
renderhas to produce.
Arriving may be playful; leaving is always quick and plain. Motion is turned
off under prefers-reduced-motion, and on a machine without a GPU the runtime
drops blur and endless animations by itself.
Words
- Title Case for titles, buttons and row titles; sentence case for descriptions.
- Name buttons after what they do: “Join”, “Forget This Network”, “Move to Trash”. Not “OK”, not “Yes”.
- An ellipsis (…) marks an action that asks for more input (“Rename…”) and a state in progress (“Connecting…”).
- Say it as a person would. “Windows is made smaller”, not “resize NTFS partition 3”.
- Typographic quotes and apostrophes: “Home”, isn’t.
- Every string goes through
tr.
Accessibility
Most of it comes with the components: every control is reachable by keyboard and shows a focus ring, clickable rows act on Enter and Space, an open sheet makes the rest of the window inert, and body text meets 4.5:1 contrast in both appearances. What the author must do:
- Label icon-only buttons and bare switches:
Button::icon_only(id, icon, label),Switch::new(…).label(…). - Never let state rest on color alone. There is no accent hue to lean on anyway: a selected thing also gains weight or a fill, “on” also moves a knob.
- Keep
Tone::Tertiaryfor text that can be missed: placeholders, fine print.
Icons
Glyphs are drawn on a 24 px grid with 1.75 px round strokes, in the text’s color. Application icons are shown as shipped, never recolored or masked.