For agents
Every page has a twin written for agents: the same rules as plain statements, with the measures and tokens as JSON.
The agent view
Choose Agent in the selector at the bottom of a page to read that page as an agent does. Add ?view=agent to a link to open a page in the agent view.
Files to fetch
Each page links to its text twin with a link element of type text/markdown, so an agent that fetches the page can find the twin.
- Index of pages and files
- /llms.txt
- Text twin of a page, as Markdown
- /agent/components/button
- Object of a page, as JSON
- The address of its twin, ending in .json
- Objects of all pages
- /agent/index.json
- Design tokens
- /tokens/werklist-tokens.json
The component object
The object of a component lists its parts with their measures, its variants and sizes, its states with their tokens, its keys and what it needs for accessibility.
{
"title": "Button",
"path": "/components/button",
"url": "https://design.werklist.com/components/button",
"text": "https://design.werklist.com/agent/components/button",
"summary": "A button starts an action on the screen you are on, from sending an offer to deleting a CV.",
"version": "2.1.2",
"kind": "component",
"name": "Button",
"purpose": "Starts an action on the current screen, such as saving a form or sending an offer.",
"use": [
"The result happens on this screen, such as a save or a dialog that opens.",
"Primary for the one action per surface (page, dialog, sheet, panel) that moves the task forward.",
"Secondary beside a primary, or for the main action when none leads.",
"Quiet for frequent minor actions in toolbars and rows.",
"Outline for an action that sits among fields, such as Add filter beside a search field: it has the fill of a text field.",
"Danger for the confirming button of a destructive step, inside its confirmation.",
"Danger quiet for a destructive action among other actions. It leads to a confirmation or offers undo.",
"Toggle: a quiet button with aria-pressed, for filters and view options in a toolbar.",
"Menu button: a chevron after the label and aria-haspopup menu, for a family of at least three related actions.",
"A call to action that opens another page: a link drawn as a button."
],
"avoid": [
"Navigation in running text: use Link.",
"A second primary button on the same surface.",
"A primary button in a table or list row.",
"A danger button as the default of a form or a dialog, or with initial focus.",
"Quiet, outline or danger quiet over a picture.",
"A setting that persists: use Switch.",
"Choosing one option from several: use Select or Segmented control.",
"A label that wraps, truncates or has no verb.",
"Two icons in one button, except the start icon and chevron of a menu button."
],
"anatomy": [
{
"part": "Container",
"measure": "height 36, 44 or 48 px, minimum width equal to the height, radius 8 px, as wide as its content",
"token": "--radius-lg"
},
{
"part": "Side padding",
"measure": "12, 16 or 20 px",
"token": "--space-3, --space-4, --space-5"
},
{
"part": "Label",
"measure": "one line, no wrap, no truncation. 13 px on 20 px at small, 14 px on 20 px at medium and large, weight 500",
"token": "--type-caption, --type-nav"
},
{
"part": "Icon",
"measure": "16 px, at most one, at the start or the end, 8 px from the label, currentColor",
"token": "--space-2"
},
{
"part": "Spinner",
"measure": "16 px, one turn per second, replaces the start icon or sits over the transparent label, appears after 300 ms",
"token": "--duration-slow"
},
{
"part": "Focus ring",
"measure": "outline 2 px, offset 2 px",
"token": "--focus-ring, --focus-ring-width, --focus-ring-offset"
},
{
"part": "Touch target",
"measure": "44 px on coarse pointers, the small size extending its hit area 4 px above and below",
"token": ""
},
{
"part": "Group",
"measure": "8 px between buttons, the primary at the trailing end. Below 640 px a form or dialog ends in a full width stack with the primary on top",
"token": "--space-2"
}
],
"variants": [
{
"name": "primary",
"use": "The one action per surface that moves the task forward."
},
{
"name": "secondary",
"use": "Cancel beside a primary, or the main action when none leads."
},
{
"name": "quiet",
"use": "Frequent minor actions in toolbars and rows. The only variant that toggles."
},
{
"name": "outline",
"use": "An action among fields, with the fill of a text field."
},
{
"name": "danger",
"use": "The confirming button of a destructive step, inside its confirmation."
},
{
"name": "danger-quiet",
"use": "A destructive action among others, leading to a confirmation or undo."
}
],
"sizes": [
{
"name": "sm",
"height": "36 px",
"padding": "0 12 px",
"type": "13 px on 20 px, weight 500"
},
{
"name": "md",
"height": "44 px",
"padding": "0 16 px",
"type": "14 px on 20 px, weight 500"
},
{
"name": "lg",
"height": "48 px",
"padding": "0 20 px",
"type": "14 px on 20 px, weight 500"
}
],
"states": [
{
"name": "rest",
"change": "Primary: brand blue fill and white label in both themes. Secondary: gray fill and text ink. Quiet: no fill and muted ink. Outline: the field material. In dark that is --glass-fill-input with an inset 1 px --input-border edge and --glass-ring, in light the 5 percent ink wash of --glass-fill-hover with no edge. Danger: --error in light and --badge-alert in dark, white label. Danger quiet: no fill and --error ink.",
"tokens": [
"--brand-true",
"--on-brand",
"--surface-control",
"--text",
"--text-muted",
"--glass-fill-input",
"--input-border",
"--glass-ring",
"--glass-fill-hover",
"--badge-alert",
"--error"
]
},
{
"name": "hover",
"change": "Primary darkens to --brand-blue-dark in light, and to the brand blue mixed 72 percent with --navy in dark. Danger drops to opacity 0.9. Secondary and outline lay --glass-fill-hover over their fill. Quiet gains --glass-fill-hover and text ink. Danger quiet gains --error at 10 percent. Only on a pointer that can hover.",
"tokens": [
"--brand-blue-dark",
"--navy",
"--glass-fill-hover",
"--error"
]
},
{
"name": "pressed",
"change": "The hover paint, on touch too, and a scale of 0.98 over 150 ms unless motion is reduced.",
"tokens": [
"--duration-fast",
"--ease-standard"
]
},
{
"name": "focus-visible",
"change": "Outline 2 px at offset 2 px in the focus ring color. As an outline it survives forced colors mode.",
"tokens": [
"--focus-ring",
"--focus-ring-width",
"--focus-ring-offset"
]
},
{
"name": "disabled",
"change": "aria-disabled true on a focusable button, drawn at opacity 0.5 in the colors of its variant. Presses and implicit form submission are canceled, and hover does not apply. Contrast minimums do not apply to a disabled button. The reason is visible text, linked with aria-describedby.",
"tokens": []
},
{
"name": "loading",
"change": "aria-busy and aria-disabled true at once, focus kept, presses ignored. After 300 ms a 16 px spinner in the label ink replaces the start icon, or sits centered over the label, which turns transparent. Width and label do not change. Under reduced motion the spinner fades between opacity 1 and 0.5 each second instead of turning.",
"tokens": [
"--duration-slow"
]
},
{
"name": "toggle on",
"change": "Quiet variant with aria-pressed true: --seg-selected fill and text ink. On hover --glass-fill-hover lies over it. In a board toolbar a pressed tool takes the brand tint instead (see Toolbar).",
"tokens": [
"--seg-selected",
"--text",
"--glass-fill-hover"
]
},
{
"name": "menu open",
"change": "aria-expanded true. The button holds its hover paint and the chevron turns 180 degrees in 150 ms, without the turn under reduced motion.",
"tokens": [
"--duration-fast"
]
}
],
"keys": [
{
"key": "Tab, Shift+Tab",
"action": "Move focus in document order, disabled and loading buttons included."
},
{
"key": "Enter",
"action": "Press. On a menu button, open the menu with focus on the first item. On a button that opens a page, follow the link."
},
{
"key": "Space",
"action": "Press on release, flip a toggle, or open a menu button's menu. Not on a button that opens a page."
},
{
"key": "Down arrow",
"action": "On a menu button, open the menu with focus on the first item."
},
{
"key": "Up arrow",
"action": "On a menu button, open the menu with focus on the last item."
},
{
"key": "Escape",
"action": "Close an open menu and return focus to the menu button."
}
],
"accessibility": [
"A native button element with type button, or type submit in a form. An a element with href when the button opens a page.",
"The name is the visible label. Icons are aria-hidden.",
"Label on fill at 4.5 to 1, icon and focus ring at 3 to 1, in every enabled state and both themes.",
"Disabled and loading use aria-disabled, not the disabled attribute, so focus stays and the reason is reachable.",
"States exposed with aria-pressed, aria-expanded, aria-haspopup, aria-busy, aria-disabled and aria-describedby.",
"Targets of 44 px on coarse pointers.",
"Forced colors: a 1 px ButtonText border, ButtonText on ButtonFace, the toggle on in Highlight, focus as an outline in Highlight."
],
"content": [
"A verb first, plus the object when the verb alone is vague: Send offer, Publish job, Add candidate.",
"Two or three words, sentence case, no final period, no exclamation.",
"Answer the question of the dialog: Delete CV and Cancel, not Yes and No.",
"Cancel stops a task and keeps nothing. Close dismisses what changed nothing.",
"No OK, no Submit, no ellipsis at the end.",
"The label does not change while loading."
],
"tokens": [
"--brand-true",
"--brand-blue-dark",
"--navy",
"--on-brand",
"--surface-control",
"--text",
"--text-muted",
"--glass-fill-hover",
"--glass-fill-input",
"--input-border",
"--glass-ring",
"--badge-alert",
"--error",
"--seg-selected",
"--focus-ring",
"--focus-ring-width",
"--focus-ring-offset",
"--radius-lg",
"--space-2",
"--space-3",
"--space-4",
"--space-5",
"--type-caption",
"--type-nav",
"--duration-fast",
"--duration-slow",
"--ease-standard"
]
}