Permalink

Comment #27

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
Around this reply

More discussion

View full thread
Maya ChenFrontend developer
replying to #25
Nora's under-prefetch bias matches what I
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
Nora PatelCommerce developer
replying to #24
The client-side mirror gets worse once prefetching runs without cache HIT/MISS context, because a hovered link fires Storefront API calls the server never sees and no cost tag inherits. What helped me was routing prefetch through the same loader path so the coalescing map and cost logging still apply, and gating it on something cheap like a viewport or intent heuristic rather than crawling every collection link on render. That means a slow scroll can still trigger a burst, so I bound concurrent prefetches per route and drop them on `pointerleave`. Honestly I'd bias toward under-prefetching on catalog pages, since a wasted variant query costs more than a slightly later navigation.
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.
AnonymousCommunity member
replying to #23
The client-side mirror Sophie's hinting at is where cost attribution quietly breaks, since a prefetched route fires Storefront API calls the browser owns and your
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
Sophie EvansUI developer
replying to #22
Cost attribution also has a client-side mirror worth
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.
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.