Skip to content

Pressable

P-05 · Primitives · Primitives

All elements · Pressable on the Primitives page

Last checked 2026-10-22 · Awaiting approval · Accessibility tests

Copies the bun run a11y:approve command for Pressable.

Pressable

P-05WCAG 2.2 AA · Passed #432

The single interaction target: focus ring, keyboard activation, hover/press/selected state, disabled semantics. Button, Chip, Tab, Menu.Item and list rows are all Pressables. Use a real <button> or <a>.

Axis Values
data-shape circle
data-icon-only · data-size square hit target / xs · sm · md
data-block full width, start-aligned (list rows)
aria-pressed · aria-selected · :disabled state
States (tab through to see the focus ring)

Guidance

When to use

  • Build a custom interactive target that needs the shared hover, press, selected, disabled and focus states.
  • Make an icon-only action, such as a row's more or close control, with data-icon-only.
  • Make a full-width, start-aligned row in a list or nav with data-block.
  • Serve as the base for Button, Chip, Tab, Menu items and list rows.

When to consider something else

  • When you need a standard labeled action with variants and colors, use Button. See Button.
  • When the action opens a list of commands, use Menu on a Button trigger. See Menu.
  • When the target toggles a setting on and off, use Toggle. See Toggle.
  • When the clickable element is a whole card or tile, use Card or an interactive Surface built on a real button. See Card.

Usability

Do
  • Use a real <button> for actions and <a href> for navigation.
  • Give every icon-only Pressable an aria-label and a Tooltip with the same name.
  • Prefer data-size="md" or the default for touch and dense lists alike; reserve xs for tight table cells.
  • Use aria-pressed for toggles and aria-selected for selection inside a list or tab set.
Don’t
  • Don't put qf-pressable on a div or span.
  • Don't use data-state in product code; it only pins states for the catalog.
  • Don't hide a disabled action that users need to discover; explain why it is unavailable.

Accessibility

Keyboard

Pressable keyboard
Keys Action
Tab Moves focus to the Pressable; Shift+Tab moves back.
Enter Activates a button or follows a link.
Space Activates a button (not a link).

Roles and names

  • Native button or a gives the role. A button that is not in a form needs type="button".
  • State is aria-pressed, aria-selected, :disabled or aria-disabled="true"; never a class.
  • Icon-only Pressables need an accessible name with aria-label; the inner icon is aria-hidden.
  • The visible label must be part of the accessible name (2.5.3).

Focus

  • The global :focus-visible rule draws --qf-focus-ring around the Pressable (2.4.7).
  • :disabled removes the Pressable from the tab order; use aria-disabled="true" when it must stay focusable to explain why. The CSS sets pointer-events: none on both, so the binding must also block activation by keyboard for aria-disabled.

Other requirements

  • Icon-only sizes come from --qf-control-height-*: xs is 1.5rem (24px on desktop), the minimum for 2.5.8; sm is 32px and md 44px. Do not shrink below xs.
  • Selected and hover backgrounds are not enough by themselves; selected also changes the text to the primary color, and the state must be exposed in ARIA (4.1.2).
  • Disabled text is exempt from contrast, but enabled text and icons need 4.5:1 and 3:1 (1.4.3, 1.4.11).
  • State changes animate for --qf-duration-fast; prefers-reduced-motion removes the transition.

Test your implementation too. This guidance covers the element as specified here. How a screen composes it (labels, order, announcements) still needs its own keyboard and screen reader check.

Accessibility tests

WCAG 2.2 AA · Passed

Passed the gate (run 358b316 on 2026-10-22): no finding in any theme. Awaiting a person’s approval of the checklist below.

Pressable test checklist
Area Automated A person checks
General Passed Color is never the only cue, text alternatives say the same thing as the graphic, and the element reads the same in the light and the dark theme.
Zoom Passed At 200% zoom, at 320 CSS pixels wide and with the WCAG text-spacing overrides, nothing is lost, clipped or overlapping.
Keyboard Passed Every row of the Keyboard table works, focus is always visible and never trapped, and the tab order follows the reading order. (3 rows)
Screen reader Passed With NVDA or JAWS on Windows and VoiceOver on macOS, names, roles and states are announced as Roles and names says, and changes are announced once. (4 items)

Approving. When the checklist passes on the checked run, record it with bun run a11y:approve -- pressable --by "Your name" and commit a11y/approvals.json with the rebuilt pages. All test status

Package

Consumers link one stylesheet, css/classic/index.css, which includes every element. The files below are where this element is defined.

Pressable package
Source css/classic/primitives/layout.css
Specimens also use Box · Card · Chip · Icon · Table · Text · Toolbar
Sprites sprites/icons.svg
React Not yet available: the React binding has not started.

Latest updates

No recorded changes yet.

All release notes