Skip to content

Button

<caos-button>

a single action

May be placed on a record page, an app’s home page, a page inside an app, an action on a record, a step of a guided flow and a seam in the workspace frame.

Name Attribute Description Type Default Required
variant variant, markup only Which of the five colour treatments to draw: primary, secondary, soft, ghost or destructive. text — one of primary, secondary, soft, ghost, destructive secondary Optional
size size, markup only Control height from the platform size scale — sm, md or lg. Inside a button group the group’s size wins, so a joined run cannot be assembled out of buttons at three heights. text — one of sm, md, lg md Optional
icon icon, markup only A glyph from the platform’s one vocabulary, drawn beside the label — or on its own, if nothing is slotted in as a label. A name the vocabulary does not carry draws nothing rather than an empty box. text none declared Optional
iconPosition icon-position, markup only Which side of the label the glyph sits on. text — one of start, end start Optional
label label, markup only What this button is, for a screen reader. Required when the button has a glyph and no slotted label, because there is then no text to read; otherwise the slotted label is the name and this is only for saying something different to it. text none declared Optional
pressed pressed, markup only A toggle, and which way it is set. Leaving it off means this is not a toggle and the control says nothing about being pressed; false is as load-bearing as true, because without it a toggle that is off cannot be told from a button that never toggles. text — one of true, false none declared Optional
loading loading, markup only This action is happening. Draws a spinner, marks the control busy for a screen reader, and stops it being pressed again. A progress statement, never a permission one. boolean false Optional
disabled disabled, markup only You may not do this. A permission statement — it should not be set because something is in flight; that is what loading is for. boolean false Optional
block block, markup only Fill the width of whatever holds it, instead of hugging its label. boolean false Optional
type type, markup only button, submit or reset. A submit or reset button forwards the action to the form around it, which a plain shadow button cannot do on its own. text — one of button, submit, reset button Optional

This piece raises no events.

Name What goes in it
the default slot The label. Leave it empty and give the button an icon to get the icon-only mode — that is the whole of what “icon button” means here.
Design token What it controls
--caos-radius The corner radius of the control.
--caos-button-radius-start The leading corners. A button group sets it to 0 to square the corners it shares with the button before it; nothing else should.
--caos-button-radius-end The trailing corners, set the same way for the button after it. Start and end rather than left and right, so a joined run reads correctly in a right-to-left script.
--caos-state-selected-bg The fill of a pressed toggle — the same one a selected row carries, so “in force” reads the same everywhere.
--caos-color-accent-fill The fill of the primary variant, and –caos-color-accent-fill-hover under the pointer.
--caos-color-accent-contrast The label and spinner of the primary variant. White by default; a brand with a pale accent sets a darker ink here.
--caos-color-danger-fill The fill of the destructive variant under the pointer.
--caos-color-danger-contrast The label and spinner of the destructive variant under the pointer.
--caos-focus-ring The ring drawn when the control has keyboard focus.
--caos-space-2 The gap between a glyph and the label.
--caos-font-display The typeface the label is set in.

Nothing else drives this piece by calling it.

Nothing on this piece can be read back.

Part Which piece of it When it is there
::part(button) the control itself Always
::part(spinner) the busy indicator drawn while loading Always
::part(icon) the glyph, when the button has one Always

One action, pressed directly. Reach for it whenever a person is meant to do a single thing from where they are standing.

  • ActionBar — A surface has several actions and one of them is the primary one.
  • OverflowMenu — The actions are secondary and belong behind a single trigger.
  • SegmentedFilter — The row of controls changes what is shown rather than doing something.

The control is a real button, so keyboard activation, focus order and the focus ring are already handled. When loading is set it is marked busy for a screen reader and cannot be pressed again. A toggle announces itself as one: pressed maps straight onto aria-pressed, and setting it to false is what tells a screen reader this is a toggle that is currently off rather than an ordinary button. What is left to the author is the LABEL: an icon-only button has no text to read, so its label attribute is the only name it has, and a label reading “Submit” on a page with three of them needs to say which one.

Every colour treatment the button has, so the one that fits can be picked by looking.

{
"id": "example",
"section": "The five variants",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "primary"
},
"children": [
"Save"
]
},
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary"
},
"children": [
"Cancel"
]
},
{
"id": "button_3",
"type": "component",
"key": "button",
"inputs": {
"variant": "soft"
},
"children": [
"Duplicate"
]
},
{
"id": "button_4",
"type": "component",
"key": "button",
"inputs": {
"variant": "ghost"
},
"children": [
"Dismiss"
]
},
{
"id": "button_5",
"type": "component",
"key": "button",
"inputs": {
"variant": "destructive"
},
"children": [
"Delete record"
]
}
]
}
<caos-button variant="primary">Save</caos-button>
<caos-button variant="secondary">Cancel</caos-button>
<caos-button variant="soft">Duplicate</caos-button>
<caos-button variant="ghost">Dismiss</caos-button>
<caos-button variant="destructive">Delete record</caos-button>

A save that is in flight: the spinner draws, the control is marked busy for a screen reader, and it cannot be pressed twice.

{
"id": "example",
"section": "Busy",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "primary",
"loading": true
},
"children": [
"Saving"
]
},
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"loading": true
},
"children": [
"Checking"
]
}
]
}
<caos-button variant="primary" loading>Saving</caos-button>
<caos-button variant="secondary" loading>Checking</caos-button>

The same two controls refused rather than busy. They look similar and mean different things, which is exactly why they are two examples and not one.

{
"id": "example",
"section": "Not allowed",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "primary",
"disabled": true
},
"children": [
"Save"
]
},
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"disabled": true
},
"children": [
"Cancel"
]
}
]
}
<caos-button variant="primary" disabled>Save</caos-button>
<caos-button variant="secondary" disabled>Cancel</caos-button>

The three control heights, taken from the platform scale rather than from the button.

{
"id": "example",
"section": "The size scale",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"size": "sm",
"variant": "secondary"
},
"children": [
"Small"
]
},
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"size": "md",
"variant": "secondary"
},
"children": [
"Medium"
]
},
{
"id": "button_3",
"type": "component",
"key": "button",
"inputs": {
"size": "lg",
"variant": "secondary"
},
"children": [
"Large"
]
}
]
}
<caos-button size="sm" variant="secondary">Small</caos-button>
<caos-button size="md" variant="secondary">Medium</caos-button>
<caos-button size="lg" variant="secondary">Large</caos-button>

A glyph beside the label, and on the other side of it. The glyph comes from the platform’s one vocabulary — there is no second set to pick from.

{
"id": "example",
"section": "With a glyph",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "primary",
"icon": "plus"
},
"children": [
"New record"
]
},
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"icon": "download"
},
"children": [
"Export"
]
},
{
"id": "button_3",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"icon": "chevron-right",
"icon_position": "end"
},
"children": [
"Next"
]
}
]
}
<caos-button variant="primary" icon="plus">New record</caos-button>
<caos-button variant="secondary" icon="download">Export</caos-button>
<caos-button variant="secondary" icon="chevron-right" icon-position="end">Next</caos-button>

The same button with nothing slotted in as a label. This is what an “icon button” is here — a mode, not a second component — and its label attribute is the only name a screen reader has for it.

{
"id": "example",
"section": "A glyph on its own",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"icon": "square-pen",
"label": "Edit"
}
},
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"icon": "share",
"label": "Share"
}
},
{
"id": "button_3",
"type": "component",
"key": "button",
"inputs": {
"variant": "destructive",
"icon": "close",
"label": "Delete"
}
}
]
}
<caos-button variant="secondary" icon="square-pen" label="Edit"></caos-button>
<caos-button variant="secondary" icon="share" label="Share"></caos-button>
<caos-button variant="destructive" icon="close" label="Delete"></caos-button>

Pressed is a state on this button, beside the busy one — not a stateful button component. The one on the right is a toggle that is OFF, which is a different thing from a button that does not toggle, and only setting pressed to false says so.

{
"id": "example",
"section": "A toggle, on and off",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"icon": "pin",
"label": "Pinned",
"pressed": "true"
}
},
{
"id": "button_2",
"type": "component",
"key": "button",
"inputs": {
"variant": "secondary",
"icon": "pin",
"label": "Pin this",
"pressed": "false"
}
}
]
}
<caos-button variant="secondary" icon="pin" label="Pinned" pressed="true"></caos-button>
<caos-button variant="secondary" icon="pin" label="Pin this" pressed="false"></caos-button>

Filling whatever holds it — how a button reads at the foot of a narrow panel or a form.

{
"id": "example",
"section": "Full width",
"columns": 1,
"items": [
{
"id": "button_1",
"type": "component",
"key": "button",
"inputs": {
"variant": "primary",
"block": true
},
"children": [
"Submit request"
]
}
]
}
<caos-button variant="primary" block>Submit request</caos-button>