Accessibility
On this page
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"andaria-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>. Itsaria-labelis 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 noaria-liveon 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 witharia-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 withrole="radio"andaria-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
”. 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 withshowModal(), 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>witharia-label="Volume pricing"andaria-describedbypointing 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-vhor 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
#ffffffon#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.
See it in action