Skip to main content
Web / React · WCAG 2.2 AA

Button (Basic)

Native button that triggers an action. Supports text-only, icon+text, and icon-only labeling patterns.

Selection

The criteria an agent checks before retrieving this component.

Use when

  • Use when the user triggers an immediate action (e.g., "Save", "Continue", "Dismiss").

Try a different component when

  • Do not use when the control navigates to a new URL (use link.basic).
  • Do not use when the control represents an on/off pressed state (use button.toggle).
  • Do not use when the control opens a menu (use menu.basic).

Must Haves

Non-negotiable structure. Every generated instance must satisfy these rules.

  • Use a native <button> for built-in semantics and keyboard behavior.
    • A custom implementation with role="button" is appropriate only when a native button cannot be used.
    • If role="button" is used instead of a native <button>, add tabindex="0" and keyboard support for Enter and Space, ensuring Space prevents page scrolling while activating the control.
  • The button has an accessible name that describes its purpose or action.
  • When the button has visible text, the visible text serves as the accessible name.
  • When additional context is needed beyond the visible text, add it via aria-label, aria-labelledby, or offscreen text. The visible text appears at the start of the accessible name.
  • For icon-only buttons, provide an accessible name using aria-label or aria-labelledby.
  • Icons within buttons must be decorative (aria-hidden="true").
  • If the action is unavailable, disable the button using the native disabled attribute. (It becomes unfocusable and non-interactive.)
  • Ensure a visible focus state (e.g., a 2px solid outline offset by 1-2px) around the button.

Donts

Avoid these accessibility and UX barriers.

  • Do not build a button out of a <div> or <span> with role="button" unless you absolutely must; native <button> is the baseline.
  • Do not create icon-only buttons without an accessible name (no unlabeled icons).
  • Do not use aria-label that conflicts with (or is wildly different from) the visible label text. Accessible names should at least begin with the visible label.
  • Do not hide focus outlines without providing a strong custom focus style.

Customizable

Alternatives and options that give the AI agent some room to move.

  • No accessibility-relevant variations beyond the Must Haves above.

Golden Pattern

The tested reference implementation. Agents start from this shape and adapt to the developer’s codebase and context.

ButtonBasicDemo.jsxJSX
export function ButtonBasicDemo() {
return (
<div>
{/* Text-only */}
<button type="button" onClick={() => alert("Saved")}>
Save
</button>

{/* Icon + text */}
<button type="button" onClick={() => alert("Downloaded")}>
<span aria-hidden="true">[icon]</span> Download
</button>

{/* Icon-only (must have accessible name) */}
<button
type="button"
aria-label="Open settings"
onClick={() => alert("Settings")}
>
<span aria-hidden="true">[icon]</span>
</button>

{/* Disabled */}
<button type="button" disabled onClick={() => alert("Won't fire")}>
Disabled
</button>
</div>
);
}

Acceptance Checks

The component’s test spec — an optional body of checks for verification.

  • Tab to the button: a visible focus indicator is present.
  • Press Space or Enter: the button activates.
  • Text-only button: screen reader announces the visible label.
  • Icon+text button: screen reader announces the text label (icon is not redundantly announced).
  • Icon-only button: screen reader announces the aria-label (e.g., "Open settings").
  • Disabled button:
    • Cannot be activated by click/keyboard.
    • Is not focusable when disabled is set.