Button
import { Button } from '@absoluteui/components/button';import '@absoluteui/components/button/style.css';Using Angular? See Button for Angular.
What it does
Section titled “What it does”Triggers an action. Button enhances a native <button>; semantics, form submission, and keyboard activation stay native. Since 0.9.0 it also enhances a link (<a href>) that should look like a button; the element stays a link.
When to use
Section titled “When to use”- Submitting forms or triggering in-page actions.
- Icon-only actions that have an accessible name.
- Actions with a busy state while an operation is pending.
When not to use
Section titled “When not to use”- Navigation to another page or URL: use a link (<a href>).
- Toggling a persistent on/off state: use Switch.
- Selecting one option among several: use a segmented control or radio group.
Examples
Section titled “Examples”Enhance an existing native button
Section titled “Enhance an existing native button”import { Button } from '@absoluteui/components/button';
const el = document.querySelector<HTMLButtonElement>('#save');if (el) { const save = Button.enhance(el, { variant: 'primary' }); el.addEventListener('click', () => { save.setLoading(true); });}Icon-only button with an accessible name
Section titled “Icon-only button with an accessible name”import { Button } from '@absoluteui/components/button';
const search = Button.create({ icon: 'search', label: 'Search', variant: 'ghost' });document.body.append(search.element);Global component defaults
Section titled “Global component defaults”import { configureAbsoluteUI } from '@absoluteui/core';import { Button } from '@absoluteui/components/button';
configureAbsoluteUI({ common: { density: 'compact' }, components: { button: { size: 'sm' } } });const b = Button.create({ text: 'Apply' });document.body.append(b.element);import { Button } from '@absoluteui/components/button';import '@absoluteui/components/button/style.css';
const b = Button.create({ text: 'Save', variant: 'primary', type: 'submit' });document.querySelector('form')?.append(b.element);More usage
Section titled “More usage”import { Button } from '@absoluteui/components/button';
const el = document.querySelector<HTMLButtonElement>('#save');if (el) { const save = Button.enhance(el, { variant: 'primary' }); el.addEventListener('click', () => { save.setLoading(true); });}Anatomy
Section titled “Anatomy”<button class="aui-button aui-button--{variant} aui-button--{size}"> [svg.aui-icon.aui-button__icon] (optional, start or end) label text [span visually hidden ", Loading"] (loading only)</button>API reference
Section titled “API reference”Factory
Section titled “Factory”Button.enhance<E extends HTMLButtonElement | HTMLAnchorElement>(element: E, options?: ButtonOptions): Button<E>; Button.create(options?: ButtonOptions & { text?: string; type?: 'button' | 'submit' | 'reset' }, doc?: Document): Button<HTMLButtonElement>Global configuration key: button (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
variant |
'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' |
"secondary" |
Visual emphasis. Globally configurable. |
size |
'sm' | 'md' | 'lg' |
"md" |
Control height and font size. Globally configurable. |
loading |
boolean |
false |
Busy state: aria-disabled, activation blocked, spinner shown, ‘Loading’ added to the accessible name. |
icon |
IconRef | null |
null |
Icon name or definition. |
iconPosition |
'start' | 'end' |
"start" |
Icon placement (logical). |
fullWidth |
boolean |
"false" |
Stretch to the full inline size of the container. |
disabled |
boolean |
Disabled state (since 0.9.0). Links: aria-disabled, removed from the tab order, activation blocked, href kept. Buttons: sets the native disabled property; unset leaves it alone. | |
label |
string |
Accessible name; required for icon-only buttons. | |
icons |
Partial<{ loading: IconRef }> |
Icon slot overrides. | |
pressed |
boolean | null |
Toggle button: aria-pressed, flips on activation; null or unset is an ordinary button (buttons only). |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
element |
E (HTMLButtonElement | HTMLAnchorElement) |
The enhanced native button or link. |
options |
Readonly<ButtonOptions> |
Current instance options. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
update(options: Partial<ButtonOptions>): void |
Merge and apply options. |
setLoading(loading: boolean): void |
Toggle the busy state. |
destroy(): void |
Remove enhancements, listeners, and subscriptions. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-change |
ButtonChangeDetail |
Yes | No | A toggle button was activated by the user: { pressed }. |
Content areas
Section titled “Content areas”| Area | Description |
|---|---|
label |
Existing child text/elements of the native button. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-button |
Base class; usable without JavaScript. |
aui-button--primary | --secondary | --outline | --ghost | --danger |
Variant modifiers. |
aui-button--sm | --md | --lg |
Size modifiers. |
aui-button--icon-only |
Square icon-only layout. |
aui-button--pressed |
Toggle button in the pressed state. |
aui-button__icon |
Rendered icon. |
aui-button__spinner |
Loading spinner; animation removed under reduced motion. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
loading |
spinner |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-active | --aui-color-border | --aui-color-border-strong | --aui-color-danger-fill | --aui-color-danger-fill-hover | --aui-color-disabled-bg | --aui-color-focus-ring | --aui-color-hover | --aui-color-on-danger | --aui-color-on-primary | --aui-color-primary | --aui-color-primary-active | --aui-color-primary-hover | --aui-color-selected | --aui-color-selected-indicator | --aui-color-selected-text | --aui-color-surface | --aui-color-text | --aui-color-text-disabled | --aui-control-height-lg | --aui-control-height-md | --aui-control-height-sm | --aui-control-padding-x | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-size-xs | --aui-font-weight-medium | --aui-icon-size-md | --aui-icon-size-sm | --aui-line-height-tight | --aui-radius-md | --aui-space-2 | --aui-space-3 | --aui-space-5 | --aui-touch-target-min
TypeScript definitions
Section titled “TypeScript definitions”type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';type ButtonSize = 'sm' | 'md' | 'lg';interface ButtonOptions { variant?: ButtonVariant; size?: ButtonSize; loading?: boolean; icon?: IconRef | null; iconPosition?: 'start' | 'end'; fullWidth?: boolean; disabled?: boolean; label?: string; icons?: Partial<{ loading: IconRef }>;}Accessibility
Section titled “Accessibility”Pattern: WAI-ARIA APG Button pattern, implemented with a native <button>.
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Enter | Button focused | Activates (native). Blocked while loading. |
| Space | Button focused | Activates on key release (native). Blocked while loading. |
| Tab / Shift+Tab | Any | Moves focus to/from the button; loading buttons stay in the tab order. |
| Element | Role |
|---|---|
| host <button> | button (native) |
| icon <svg> | none (aria-hidden=true) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-disabled |
host | “true” while loading (button remains focusable) |
aria-label |
host | Set from label; includes ‘, Loading’ while loading |
Native focus. Visible :focus-visible outline using color-focus-ring (>= 3:1 against surfaces).
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”| Criterion | Level | Note |
|---|---|---|
| 1.4.3 Contrast (Minimum) | AA | |
| 1.4.11 Non-text Contrast | AA | |
| 2.1.1 Keyboard | A | |
| 2.4.7 Focus Visible | AA | |
| 2.5.3 Label in Name | A | |
| 2.5.8 Target Size (Minimum) | AA | |
| 4.1.2 Name, Role, Value | A |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- The loading state is conveyed through visually hidden text in the accessible name rather than aria-busy, which buttons do not reliably announce.
- Disabled (native) buttons are removed from the tab order by the browser; loading buttons are not.
- Screen-reader announcement of the name change when loading starts while focused has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Behavior
Section titled “Behavior”States
Section titled “States”default, hover, active, focus-visible, disabled (native disabled; disabled option on links), loading, pressed (toggle buttons: aui-button--pressed).
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| default | setLoading(true) / update({ loading: true }) |
loading (activation blocked, stays focusable) |
| loading | setLoading(false) |
default |
| any | native disabled = true |
disabled (removed from tab order by the browser) |
| any (link) | update({ disabled: true }) |
disabled (aria-disabled, tabindex="-1", activation blocked; the previous tabindex returns on enable) |
Accessibility notes
Section titled “Accessibility notes”- Loading is conveyed through the accessible name because
aria-busyis not reliably announced on buttons. - Icon-only buttons without an accessible name are rejected at construction (
BUTTON_ICON_ONLY_LABEL). - Minimum target size is 1.5rem (WCAG 2.5.8); compact
smbuttons are 1.75rem high. - Manual screen-reader verification is pending (see Known limitations).
Responsive behavior
Section titled “Responsive behavior”Inline-flex; the label does not wrap. Density tokens (compact, comfortable, spacious) change control height and padding.
Right-to-left
Section titled “Right-to-left”Logical properties throughout; iconPosition: 'start' places the icon at the inline start in both directions.
Theming
Section titled “Theming”Colors come from role tokens only. Verified in light, dark, and high-contrast themes (axe, WCAG 2.2 AA). In forced-colors mode, borders use ButtonText, disabled uses GrayText, and focus uses Highlight.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { button: { variant: 'primary', size: 'sm' } } });Global changes apply to existing instances immediately.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic.
icon accepts a name resolved through the global icon provider/registry or an inline IconDefinition. The icons.loading slot defaults to spinner.
Security
Section titled “Security”Button.create sets text with textContent, so HTML strings are never parsed. No inline styles, eval, or injected <style>; verified under a strict CSP with Trusted Types enforced.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry.
Performance
Section titled “Performance”One capture-phase click listener and one configuration subscription per instance. Budget: under 0.5 ms average per Button.enhance across 1,000 instances in headless Chromium (performance test).
Supported data scale
Section titled “Supported data scale”1,000 buttons per page in the performance test.
Edge cases
Section titled “Edge cases”- Enhancing a button whose only child is an icon requires
label,aria-label, oraria-labelledby. - A
type="submit"button does not submit its form while loading. - A link host without
hrefis not a link (no role, not focusable); give it anhref. - A disabled or loading link blocks click handlers registered after enhancement, including router link handlers on the same element; modified clicks are blocked too.
- Calling
update({ variant })with an invalid value throws, and the previous rendering stays in place.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
BUTTON_HOST |
configuration | Host is neither a <button> nor an <a>. |
BUTTON_ICON_ONLY_LABEL |
configuration | Icon-only button without an accessible name. |
CFG_INVALID_VALUE / CFG_UNKNOWN_OPTION |
configuration | Invalid or unknown option; the message names the property and expected type, never the value. |
A failed construction leaves no listeners or subscriptions behind.
Known limitations
Section titled “Known limitations”- Capture-phase click listeners that a consumer registers on the same element before enhancement still run while loading.
- Screen-reader behavior of the loading name change has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Unsupported scenarios
Section titled “Unsupported scenarios”- Hosts other than
<button>and<a>(for example adivwithrole="button"). - HTML strings as labels.