The components ship accessible by default - you don’t add ARIA for the basics:
- Volume-discount tiers are a keyboard radiogroup.
volume-tier-listsetsrole="radiogroup"- an
aria-label(the discount title, unless you supply your ownaria-label/aria-labelledby); eachvolume-tierrow is arole="radio"witharia-checked, rovingtabindex(the selected row is the single tab stop), andss-active, driven by Arrow/Home/End/Space with selection following focus (the same radio-group pattern aschange-optionswatch mode). The row’s accessible name comes from itsshow-tier-*text.
- an
- Mix & match sections are an APG disclosure.
toggle-sectionresolves the focusable control (your nested<button>, else the upgraded host) and setsaria-expanded+aria-controlspointing at the section’smix-match-item-list, which owns the matching deterministicidand the nativehiddenwhile collapsed - so a collapsed pool is genuinely removed from the accessibility tree, not just visually hidden.show-section-progressis a realrole="progressbar"(aria-valuemin/-valuenow/-valuemax) toward the section’s requirement.add-mix-match-itemandadd-mix-match-to-cartproject availability / capacity / completeness asaria-disabledon their control.show-pick-imagewritesalt= the product title;show-section-imageis decorative (alt=""). Not automatic: a name for the icon-only steppers - see “What you still own” below. - The add-ons row toggle is native-first.
select-addonuses a nested<input type="checkbox">as its control when you provide one (the recommended markup - pair it with a label or give the input anaria-label); a nested<button>/<a>becomes an APG toggle button (aria-pressed); a bare host upgrades itself torole="checkbox"+tabindex+ Enter/Space witharia-checkedtracking the row. Availability projects asaria-disabledon the control (ticking ON is blocked while the card’s variant is unbuyable; ticking OFF always works) withss-out-of-stock/ss-unavailableon the wrapper for CSS. - The subscription selectors are APG toggle buttons - on the PDP and in the cart alike.
All four (
change-purchase-option/change-selling-planand their in-cart counterpartschange-line-purchase-option/change-line-selling-plan) resolve a focusable control per option (your nested<button>if you provide one, else thepurchase-option/selling-plan-optionhost upgraded torole="button"+tabindex+ Enter/Space) and setaria-pressedon it - mirroring[ss-active], written deterministically every update - so the current mode / active frequency is exposed to AT. The two pairs behave identically; the only difference is scope (product vs cart line). The SSR fill stamps the same attributes in the same order, so a server-rendered PDP selector is keyboard-operable before hydration too. Their names come from the option’s own text (the pill label; the engine-filledshow-selling-plan-name/show-selling-plan-price), so give eachpurchase-optionvisible text. As everywhere else in the library, a nested native<button>is respected and preferred (see “prefer nesting a native<button>/<a>” below) - but a bare pill is now a real control either way. - Action/nav controls are keyboard-operable and named.
add-to-cart,buy-now,add-bundle-to-cart,add-volume-to-cart,open-cart,close-cart, the quantity steppers, the cart-line controls,show-thumbnail, andproduct-linkresolve a focusable control: a nested native<button>/<a>if you provide one (recommended - the element then projects sold-out/disabled state + the label onto it), else the element upgrades itself torole="button"/"link"+tabindex+ Enter/Space. Icon controls get anaria-labelautomatically (“Increase quantity”, “Remove item”, …). show-thumbnailexposes the selected thumbnail viaaria-current; images writealtdeterministically; external-video<iframe>s get atitle.- Inputs are labelled -
input-quantity(aria-label="Quantity"+ min/max) andsearch-input(aria-label, override via thelabelattribute). - Markets pickers name their control - in select mode
change-country/change-languageset anaria-labelon the generated<select>(from thelabelattribute, else"Country"/"Language") when the author supplies no name and disable it during a switch. In template (pill) mode the picker makes the pill container a keyboard radiogroup:role="radiogroup"aria-label(the author’s ownaria-label/aria-labelledbywins, else thelabelattribute), eachlocale-valuegetsrole="radio"+aria-checked, rovingtabindex(the selected pill is the single tab stop), Arrow/Home/End/Space keys with selection following focus (identical tochange-optionswatch mode), andaria-disabledon the pills while a switch is in flight. Both modes setaria-busyon the picker during the switch and inject a visually-hiddenrole="status"live region announcing the settled market/language.
When building or auditing, prefer nesting a native <button>/<a> in the action/nav tags,
and don’t hand-add role/tabindex to them - the library does it. The full standard
(WCAG 2.2 AA + ARIA APG, by archetype) is the library’s accessibility guide.
All three change-option modes are accessible: swatch is a keyboard radiogroup (Arrow
keys + roving focus, aria-checked, aria-disabled on unavailable values); the <select>
and native-radio modes get a programmatic group label (role="radiogroup"/aria-label) plus
the unavailable state projected onto the native control (aria-disabled on radios, disabled
on unavailable <option>s - combinations that don’t exist or are out of stock, the same
unavailability the swatch/radio modes mark). (Still in progress: the cart drawer dialog and the
predictive-search combobox.)
What you still own (the library does NOT do it for you): two things, both enforced as SSK-501.
- Unnamed fields. A few controls use your
<input>/<textarea>verbatim and never name itapply-discount,cart-note,klaviyo-back-in-stock, andchange-price. Give each an accessible name (aria-label, a wrapping<label>, or a<label for>; a placeholder is not a name).
- The icon-only mix & match steppers.
increase-mix-match-item,decrease-mix-match-item, andremove-mix-match-itemare deliberately not self-labelled (a generic label would be wrong per card), so ”+” / ”−” / ”×” is all a screen reader gets. Put anaria-labelon the element or its nested<button>- e.g.aria-label="Increase quantity". (add-mix-match-itemnormally carries visible text and needs no extra label.)
Also provide real alt on any images you add outside the show-* media tags, and keep a sane
heading order.
Imported from the Storesynk skill v0.1.0 (references/component-reference.md). To change this page, change it there.