Permalink

Comment #30

Daniel BrooksFull-stack developer
replying to #29
The ordering issue isn't really screen reader queueing, it's how you write into the region. Assembling a message with incremental DOM edits like appendChild or updating a child span makes the AT treat each mutation as a separate change, so prefetch and selection writes interleave into fragments. Swapping
Around this reply

More discussion

View full thread
Leo MartinWeb developer
replying to #28
The `aria-busy` placement problem gets sharper once `<content-visibility: auto>` enters the picture, since off-screen card subtrees aren't rendered until they scroll near the viewport, which means a live region living inside one of those subtrees can be skipped entirely at the moment it's needed. I've had better luck hoisting a single polite status region to the top of the product shell, outside the content-visibility container and outside anything cacheable, then having selection and prefetch logic write into it by id. That keeps announcements working on slow mobile connections where a tap lands before the query resolves. Curious whether anyone has seen screen readers queue those updates out of order when prefetch and selection both write in quick succession.
Nora PatelCommerce developer
replying to #30
The live-region write mechanism Daniel describes also determines what survives a cache purge, which is the part I keep tripping over on catalog routes. If the region's initial content is server-rendered as a placeholder string, that string is now part of the cached fragment, and a shopper who arrives on a HIT can hear the stale placeholder announced before any client query resolves. What I've moved to is leaving the region genuinely empty in the shell and seeding it only from the component that owns the selection query, so there's no cached text for the AT to read at all. The cost is losing the "loading" cue during the gap between mount and first write. I've been filling that with a visually hidden `<output>` element tied to the form, which browsers announce on value change without needing a cached initial state.
AnonymousCommunity member
replying to #27
Sophie's `aria-busy` swap is right, but where it lands matters more than swapping the attribute: an `aria-busy` on the focused button itself is announced inconsistently across screen readers, so the loading state can be silent even while it's technically present. What has held up better is keeping the button's name stable and putting busy state in a
Maya ChenFrontend developer
replying to #31
The `<output>` swap is clean, but its `for` associations are the part that bites: those ids ship inside the cached shell, so any client-side reordering or re-keying of the form controls silently orphans them, and the announcement just stops with no error. I've started deriving variant input ids from the option name and value (`size-medium`) rather than array index, since an index shifts the moment a merchandiser reorders options in the admin. It also means the `for` list stays meaningful across HIT
Sophie EvansUI developer
replying to #26
The mobile side of Maya's per-operation cost row is where I keep landing, because a slow connection turns "invisible round trip" into a visible one: tap a size, and the button sits enabled but unresolved for a second or two. I've stopped using `aria-disabled` for that window and emit `aria-busy` instead, since announcing "unavailable" while a query is in flight is a lie a screen reader user can't easily verify. On long collection pages I also wrap card subtrees in `content-vis
AnonymousCommunity member
replying to #32
The id-derivation point has a schema side nobody's touched: `size-medium` breaks the moment a merchandiser renames an option value from "Medium" to "M" or introduces a value that collides after normalization, like "One Size" and "one-size". Since those ids are baked into the cached shell and into any `for` association, the orphan only shows up after a publish, not at build time. What I've leaned toward is deriving from the variant's stable Shopify GID instead, with the human-readable slug kept only as a fallback attribute for debugging. It makes the ids opaque and uglier to read in devtools, but a variant id survives renames, translations across markets, and option reordering, which is roughly every edit that currently costs you a silent announcement regression.
Maya ChenFrontend developer
replying to #25
Nora's under-prefetch bias matches what I
Sophie EvansUI developer
replying to #33
Delivery context is a variable those GIDs don't capture: the same variant id resolves to different availability and price depending on market and currency, so if the cached shell is keyed without those dimensions you're shipping an id that's stable but whose meaning isn't. A returning shopper on a HIT can hear a price the cart then rejects at checkout, which is worse than a missing announcement
Join the discussion

Leave a comment

Name and message are required. Website is optional. Public website links use rel="ugc nofollow" to reduce comment spam.