Design system

Components

Every component in the design language, in each state that applies. The styles use only tokens.css, and the markup carries the roles and states a React or Vue version should copy. Component specs describe each one; decisions say why.

Each component’s badge names its layer: a new project adopts Core as it is, with its own hue and fonts set in the tokens.css identity block, and replaces Identity with its own look. The first specimen in each row is live. The others pin one state for display and do not respond, and every caption names its state.

By purpose

Actions

  • ButtonThe main action control: primary, secondary, ghost, danger, and text.
  • Quiet actionA small transparent action inside a component, such as Copy or Close.

Selection

Inputs

Feedback and status

  • ProgressShow how far a task has got.
  • ScoreShow a value out of a maximum.
  • BadgeA short status label.
  • AlertA real caveat or status message in the page.

Containers and overlays

  • Surface and cardPanels and cards for parallel, comparable content.
  • FigureAn image or diagram with a caption.
  • DialogA modal task that needs an answer before the page continues.
  • DrawerA side panel, such as phone navigation.

Navigation

  • Navigation listRows of links with current page and current location.
  • Section railA sticky list of sections that moves into a drawer on phones.
  • Find fieldFilter a navigation list as you type.
  • BreadcrumbsThe path from the site to this page.
  • PagerPrevious and next pages in a sequence.
  • TabsSwitch panels about one object, without leaving the page.
  • Skip linkJump past the header to the content.
  • Keyboard keyShow a key or shortcut in text.

Code and examples

  • Code blockSource code with an optional header and Copy, and a live example above it.

Identity: terminal folio

Actions

Start, confirm, or cancel something.

Button

CoreSpec

The main action control: primary, secondary, ghost, danger, and text.

Do
One primary button in each decision group, labelled with a verb for its result, such as “Save changes”. Every other action in the group is secondary, ghost, or text.
Don’t
The danger variant on an action the reader can undo. Danger marks an action that destroys something.

Primary

Rest
Hover
Focus visible
Pressed
Busy
Disabled

Secondary

Rest
Hover
Focus visible
Pressed
Disabled

Ghost

Rest
Hover
Focus visible
Pressed
Disabled

Danger

Rest
Hover
Focus visible
Pressed
Disabled

Text

Rest
Focus visible
Disabled

Sizes

sm
md
lg
sm
lg

Link

Read the guideRest, live; no underline on hover
Read the guideFocus visible; no disabled state

Quiet action

CoreSpec

A small transparent action inside a component, such as Copy or Close.

Do
Use it for an action inside a component: Copy in a code block or command list, close in a dialog or drawer, Full size on a capture, and the project trigger.
Don’t
An action that stands on its own in the page, such as Save or Next. That is a button.

One recipe for Copy, Full size, dialog and drawer close, and the project trigger. Each component sets only its size and place.

Icon

Rest
Hover
Focus visible
Pressed

Text

Rest
Hover
Focus visible
Pressed
Disabled, live; no hover or press fill

Selection

Choose options or turn something on.

Checkbox and radio

CoreSpec

Pick several options, or one from a short list.

Do
Checkboxes for options the reader can pick in any combination. Radios for one choice from a short list that stays in view.
Don’t
A label written as a question, such as “Send updates?”, or as a negative, such as “Don’t email me”. Name the option: “Email me updates”.

Checkbox

Rest
Checked
Focus visible
Disabled
Disabled, checked

Radio

Rest, live
Focus visible
Disabled

Sizes

sm
md
lg

Radio card group

CoreSpec

Pick one option that needs a description.

Do
Use radio cards when the reader chooses by a description, such as plans or deploy modes. Give each card a title and one line on what differs.
Don’t
Radio cards for options that a title alone explains. Use radios.

Live

Delivery
Rest; Immediate is selected

Pinned

Delivery, pinned
Hover; selected with focus visible
Delivery, disabled
Disabled; unselected with focus visible

Switch

CoreSpec

Turn a setting on or off at once.

Do
Use a switch for a setting that applies the moment it changes. Its label names the setting, such as “Dark mode”, and stays the same when on or off.
Don’t
A switch in a form that applies on submit. Use a checkbox there.

States

Off, live
On
Focus visible
Disabled
Disabled, on

Sizes

sm
md
lg

Toggle button

CoreSpec

A labelled card that latches on, with a switch inside.

Do
Use it for an on or off option whose label sits inside the control, such as “Wrap lines” in a viewer’s toolbar.
Don’t
A toggle button for an action that runs once, such as Refresh. It stays on until pressed again; an action is a button.

States

Rest, live
Hover
Pressed
Focus visible
Disabled

Sizes

sm
md
lg

Segmented control

CoreSpec

Two to five short options that apply at once.

Do
Use it for two to five short options that apply at once and change how the same content shows, such as a view mode or the System, Light, and Dark choice.
Don’t
A segmented control that switches between panels of content. Use tabs.

The live control glides its thumb between options: 260ms for the leading edge, 300ms for the trailing edge. The theme picker at the top uses the same script, and it does not glide when the page loads a saved choice.

Text

Rest, live
Hover on Board
Focus visible on Board
Disabled

Icon only and sizes

Icon only, live
sm
lg

Inputs

Enter text and values.

Text input and textarea

CoreSpec

Type a short value or a longer note.

Do
A textarea for an answer longer than one line, and type="search" for a field that filters.
Don’t
A label or an instruction that lives only in the placeholder. It disappears as the reader types.

Input

Rest
Focus visible
Disabled

Enter a service name.

Invalid

Enter a service name.

Invalid, focus visible

Search

Live; focus it to show the clear cross, which darkens on hover
Focus visible

Sizes

sm
md
lg

Textarea

Rest
Focus visible
Disabled

Add a note.

Invalid

Select

CoreSpec

Choose from a longer list.

Do
Use a select for one choice from more than five options, in a predictable order: alphabetical, numeric, or by frequency of use.
Don’t
A first option that acts as the label, such as “Choose a region”. The label goes above the field.

Closed

Rest
Focus visible
Disabled

Choose a window.

Invalid

Sizes

sm
md
lg

Open picker

Field wrapper

CoreSpec

Label, description, and error text around a field.

Do
Write the error as the fix, such as “Enter a date after today”, and the description as a format or limit, such as “Up to 64 characters”.
Don’t
A description that repeats the label, or an error that only says “Invalid”.

Description and error

Milliseconds at p95.

With description

Enter a positive number.

Error replaces the description

Slider

CoreSpec

Set a value in a range.

Do
Use a slider for an approximate value in a range, such as volume or opacity, and show the current value as text beside it.
Don’t
A slider for a value the reader must set exactly, such as a port or a price. Use a text input.

States

40%
Rest, live
60%
Focus visible
60%
Disabled

Sizes

50%
sm
50%
md
50%
lg

Feedback and status

Show state, progress, and caveats.

Progress

CoreSpec

Show how far a task has got.

Do
Use it for a task with a known end, such as an import, and name it for the task.
Don’t
A progress bar for a measured value, such as disk usage or a rating. It shows a task moving to its end; use text or a score.

Values

0%
40%
100%

Score

CoreSpec

Show a value out of a maximum.

Do
Use it for a value out of a fixed maximum, such as 4/5, and keep one maximum across a list so the rows compare.
Don’t
A score for a percentage or an open-ended count. Write the number as text.

Values

3/53 of 5
5/55 of 5

Badge

CoreSpec

A short status label.

Do
A one- or two-word status or category on an item, such as “Healthy” or “Beta”, with a status tone only when it is a status.
Don’t
A badge that repeats the title, or one on every row with the same value. Badge the exceptions.

Tones

No dataNeutral
HealthySuccess
WarningWarning
AlertingDanger
RunningInfo

Alert

CoreSpec

A real caveat or status message in the page.

Do
Use an alert for a caveat or status message the reader needs before acting. When action is needed, name it, such as “Reconnect the source to resume sync”.
Don’t
An alert for decoration or routine emphasis. A short status label is a badge; explanations and recovery instructions stay in an alert.

Tones

Values are sampled every 5 minutes.

Neutral

The monitor recovered at 14:20.

Success

No data for 42 minutes. Check ingestion before you trust this monitor.

Warning

The webhook returned 500 three times.

Danger

A new baseline is ready to review.

Info

Containers and overlays

Group content, or lay a task over the page.

Surface and card

CoreSpec

Panels and cards for parallel, comparable content.

Do
Use cards for a few parallel, self-contained items that a reader compares, such as plans or projects.
Don’t
A panel inside a panel, or cards around ordinary prose.

Card

API p95 latency

Alerting
412 ms against a 300 ms threshold for 10 minutes.
checkout-apiUpdated 2 minutes ago
Header, body, and footer

Surface

Default padding
Default
Compact padding
Compact

Figure

CoreSpec

An image or diagram with a caption.

Do
Caption every figure with what it shows. When the prose refers to one figure by number, number them all.
Don’t
A screenshot of code or of a component. Show code as text, so the reader can copy it, and a component live.
HealthyWarningAlerting
Figure 1. A well with its caption below.

Dialog

CoreSpec

A modal task that needs an answer before the page continues.

Do
Use a dialog for a short task the reader must finish or cancel before the page continues, such as confirming a deletion. Title it with that task.
Don’t
A dialog that opens without the reader asking, such as on page load, or one that holds a long form. A long form gets its own page.

Live

Opens a native modal dialog

In place

Static specimen; the real one sits over an --color-overlay backdrop

Drawer

CoreSpec

A side panel, such as phone navigation.

Do
Use a drawer for navigation or supporting detail that slides in from the side its trigger sits on, such as phone navigation, and open it from a named button.
Don’t
The page’s main task inside a drawer. The drawer holds navigation or detail; the task stays on the page.

Live

Rest, live: a page’s contents trigger opens a side drawer

In place

Open, pinned; Button is the current section

Navigation

Move between pages and sections, and find things.

Section rail

CoreSpec

A sticky list of sections that moves into a drawer on phones.

Do
Use a rail for the sections of a long page, or for a site’s pages. A site’s pages may take a navigation strip of 6 links or fewer instead.
Don’t
A rail beside a strip or a contents list that holds the same links. Each level has one list.

Desktop rail

Live; Slider is the current section
Collapsible groups: Inputs open, Feedback closed

Phone header

Rest at tablet width: the switcher and appearance, then the pages, then the labelled trigger below the header
Phone, two links: text links after the switcher, Docs current; where the row is full, only the picker wraps. A documentation page hides them, and its footer carries them

Find field

CoreSpec

Filter a navigation list as you type.

Do
Use it at the top of a long navigation list, such as a section rail, to filter its rows by name or purpose.
Don’t
A find field used as a site-wide search. It matches only the rows of the list it filters.

States

Rest, live; the key hint shows the shortcut
3 matchesFocus visible with a query; the hint hides

No component matches tooltip.

No matches
Rest, shortcuts off: no hint

Pager

CoreSpec

Previous and next pages in a sequence.

Do
Use a pager for pages a reader goes through in order, such as a guide’s chapters or the skills in one group.
Don’t
A pager on pages with no reading order, or one per section on a page with a section rail.

Sequence

Rest, live; previous and next
First page: next only, still at the end; hover

Tabs

CoreSpec

Switch panels about one object, without leaving the page.

Do
Use tabs for panels about one object, such as a monitor’s Overview and History, when the URL does not change.
Don’t
Links with role="tab", or one set that mixes pages and panels. Pages take a navigation strip.

Live

Overview

Arrow keys move between tabs; Home and End jump to the ends.

History

Seven days of evaluations.

Settings

Threshold and notification settings.

Live; Overview is selected

Pinned

Hover on History
Focus visible

Keyboard key

CoreSpec

Show a key or shortcut in text.

Do
A key or shortcut in running text or shortcut docs, one key per <kbd>.
Don’t
A key style for code or button names. Code takes <code>; a button’s name is plain text.

Keys

Press / to find, Esc to clear, and Enter to go to the first match.

Rest, in running text

Code and examples

Show source and live examples.

Code block

CoreSpec

Source code with an optional header and Copy, and a live example above it.

Do
Use a code block for source with no live result. When the reader should see the result too, use the variant with a live example.
Don’t
The same language label on every block of a page. Put useful setup context above the block instead.

Source well

monitor.tsTypeScript
1const threshold = 300 // ms at p952export const name = 'API p95 latency'
Header, line numbers, and Copy, live
import { threshold } from './monitor'
Compact, with focus visible on Copy

With a live example

<button class="btn secondary" type="button">Cancel</button><button class="btn" type="button">Save monitor</button>
Live: the stage on the page background, the source below one hairline, and Copy in its corner

Identity: terminal folio

The personal sites’ look. A new project replaces these with its own.

Command plate

IdentitySpec

A shell command on a hue-tinted plate.

Do
Use it for a shell command the reader runs, one command per line.
Don’t
A $ typed into the command. CSS draws the prompt; a typed one is copied with the command.

Commands

brew install filipgutica/tap/filip-stack
Compact, live; the $ is drawn by CSS
Set up
pnpm install --frozen-lockfilepnpm check
With a header, two lines
filip-stack apply
Focus visible on Copy, in --color-project-dark

Terminal capture

IdentitySpec

A recorded terminal screen with a status line.

Do
Use it to show what a command prints, one tab per capture, with the path and branch in the status line.
Don’t
A capture for a screenshot of a graphical app. Use a figure.

status

● host-config   3 targets current
● field-guide   synced 2 minutes ago

~/code/filip-stack · main

diff

tokens.css  +12 −4

~/code/filip-stack · docs/design-catalogue

Page type and helpers

IdentitySpec

Mono headings, steps, definitions, facts, and the footer.

Do
Use steps for a sequence the reader follows in order, definitions for terms with short meanings, and facts for short labels and values.
Don’t
The ## mark on an application screen, or on h3 and lower.

Headings

~/annoterm

Display title, mono

Install

Section heading with its ## mark

Steps

  1. Install the CLI

    Homebrew installs the launcher.

  2. Apply host config

    It copies the guidance and the design system.

Rest: two steps

Facts

Installed to
~/design-system
Source
@filipgutica/design-system
Rest: two facts

Definitions

--all
Apply every target, including skipped ones.
--home
Install into another home directory.
Rest: two terms

Command list

CommandUse it for
filip-stack statusCompare host files with the repository.
filip-stack applyInstall the current host config.
Rest: two commands

Control states

The interactive states each control’s spec defines. Selected covers checked, on, and current. Components with no interactive states are left out.

ComponentHoverPressedSelectedFocusDisabledBusyInvalid
ButtonYesYesNoYesYesYesNo
Quiet actionYesYesNoYesYesNoNo
Checkbox and radioNoNoYesYesYesNoNo
Radio card groupYesNoYesYesYesNoNo
SwitchNoNoYesYesYesNoNo
Toggle buttonYesYesNoYesYesNoNo
Segmented controlYesYesNoYesYesNoNo
Text input and textareaNoNoNoYesYesNoYes
SelectNoNoNoYesYesNoYes
Field wrapperNoNoNoNoNoNoYes
SliderNoNoNoYesYesNoNo
Navigation listYesNoYesYesNoNoNo
TabsYesNoYesYesNoNoNo

Delete monitor

This removes its history.

API p95 latency stops alerting at once. Escape closes this dialog and returns focus to its trigger.

Capture

Contents