# Accessibility

> The roles, labels, keyboard support and live regions built into each AndOr widget, and what to keep when you restyle.

Source: https://backtrackhq.com/docs/developers/accessibility/

AndOr widgets use real HTML controls, labels and live regions, so they
work with a keyboard and a screen reader. This page lists what each
widget does, so you keep it when you restyle.

## Per widget

### Sale price

- The host has `aria-live="polite"` and `aria-atomic="true"`, set in
  Liquid. It announces only when the sale amount changes, never at page
  load.
- Both amounts carry a visually hidden label, "Regular price" and "Sale
  price".

### Savings badge and code chips

- A visually hidden "Discount" label leads the badge.
- A code is a real `<button>`. Its `aria-label` is the full sentence, for
  example "Copy discount code AUTUMN15".
- Copying confirms in two ways: the button text changes to "Copied", and
  a `role="status"` element announces it. Focus stays on the button.
- The applied check mark is `aria-hidden="true"`. The words say
  "applied", so the state is not shown by color alone.

### Countdown

- `role="timer"`, and no `aria-live` on purpose. A live region would
  announce every tick. A timer is read when the shopper moves to it.
- A visually hidden "Sale countdown" label names it.

### Offers list

- The heading level is a block setting (default `h3`, or plain text).
- The list is a real `<ul>`, linked to its heading with
  `aria-labelledby`.
- Codes are real buttons, the same as on the badge.

### Volume table and volume picker

- The table's current row has `aria-current="true"`.
- The picker cards are a radio group (`role="radiogroup"`, cards with
  `role="radio"` and `aria-checked`). One card holds the tab stop, the
  arrow keys move the choice, and Space or Enter picks.
- The List, Mini buttons and Boxes layouts use real radio inputs in a
  `<fieldset>`, so Tab and the arrow keys work natively.
- The line under the picker ("Add 1 more and get 15% off") is a polite
  live region.

### Goal bar

- The track has `role="progressbar"`.
- The sentence is a polite live region, so a screen reader hears the new
  amount after a cart change.

### Discount callout and collection banner

- Both have `role="note"`.

### Cart claim rows and gift slot

- Claim is a real button named "Claim <product>". A variant choice is a
  labelled `select`.
- While a gift is being added for the shopper, the box has
  `aria-busy="true"`.
- After a redraw removes the button the shopper pressed, focus moves to
  the box's title (`tabindex="-1"`), so the next Tab starts there. The
  title draws no focus outline on purpose. Do not add one back.

### Gift chooser

- A native `<dialog>` opened with `showModal()`, so focus is trapped and
  the page behind it is inert.
- Each option is a `<fieldset>` of real radio inputs. Arrow keys move
  within a group, Tab moves between groups.
- A sold-out value is disabled, and its accessible name ends with "Sold
  out".
- Escape closes the chooser and leaves the cart drawer open. Focus
  returns to the button that opened it.

### Product card recipes

- The complete price recipe labels both amounts for screen readers.
- The volume hint's info icon is a real `<button>` with
  `aria-label="Volume pricing"` and `aria-describedby` pointing at the
  step list. The list shows on hover and on keyboard focus.

## Reduced motion

The widget stylesheets that move (the skeleton shimmer, the goal bar
fill, the gift chooser sliding up on phones) stop that motion under
`prefers-reduced-motion: reduce`.

## Visually hidden text: `.andor-vh`

`.andor-vh` is AndOr's visually hidden class. `.andor-price__label` and
`.andor-code__status` are aliases of it. It hides labels and status text
from sight but keeps them for screen readers.

> **Caution:** Do not restyle `.andor-vh` or its aliases. Removing the
> clipping prints screen-reader-only text into the page.

## When you restyle

- **Check contrast.** Target at least 4.5:1 for normal text. The pairs
  that matter: badge text on badge background, and the sale price,
  countdown and offers accent on the section background. The shipped
  default is `#ffffff` on `#c0392b`.
- **Keep focus visible.** The picker cards show an outline on
  `:focus-visible`. Do not remove it.
- **Do not force hidden parts back on.** A hidden part is meant to be
  hidden for everyone, including screen readers.
