Skip to content

a11y(4.1.2): Table / ProgressBar / Loading primitives — expose aria-busy on data-refresh regions#3555

Merged
ardiewen merged 6 commits into
mainfrom
wcag/4.1.2-aria-busy-loading-regions
Jul 6, 2026
Merged

a11y(4.1.2): Table / ProgressBar / Loading primitives — expose aria-busy on data-refresh regions#3555
ardiewen merged 6 commits into
mainfrom
wcag/4.1.2-aria-busy-loading-regions

Conversation

@rosanusi

@rosanusi rosanusi commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Sets aria-busy on regions that are actively loading or refreshing data, so AT users have a programmatic signal distinguishing "data is current" from "data is being updated."

Before: grep -r aria-busy src/ returned zero matches. Screen-reader users had no signal when tables refreshed, skeleton loaders appeared, or polling intervals fired.
After: Three primitives carry permanent or reactive aria-busy, and three polling consumers wire a reactive isPolling/isChecking flag.

Changes

Foundation primitives

  • table.sveltearia-busy={updating ? 'true' : undefined} on <table>. The updating prop already drives the visual <ProgressBar> in <thead>; this surfaces the same state programmatically.
  • progress-bar.svelterole="progressbar" + aria-busy="true" on the meter div. The bar's presence always implies busy; the role and attribute make it machine-readable.
  • loading.sveltearia-busy="true" + aria-live="polite" on the skeleton container. The aria-live lets AT announce load completion when the skeleton unmounts and real content renders.

Consumer wiring

  • workflow-run-layout.svelteisPolling state flips true at the start of the 10 s poll interval, resets via queueMicrotask after throttleRefresh(). The event-history slot wrapper carries aria-busy={isPolling}.
  • status-counts.sveltearia-busy={countPoller.loading} on the status-count container. countPoller.loading is already tracked by createCountPoller; no new state needed.
  • worker-details.svelteisCheckingHeartbeat state flips around the 10 s heartbeat staleness check interval via the same queueMicrotask pattern. The <section aria-label="worker-details"> carries aria-busy={isCheckingHeartbeat}.

Test plan

  • Workflows list: set updating={true} on a Table consumer and inspect DOM — confirm <table aria-busy="true">; confirm aria-busy disappears when updating={false}
  • Skeleton/Loading: confirm data-testid="loading" container has aria-busy="true" and aria-live="polite" while visible; no stale aria-busy after unmount
  • Workflow detail page: wait for the 10 s poll cycle; confirm the event-history wrapper alternates aria-busy="true" (during poll) → no attribute (after poll)
  • Worker detail page: wait for the 10 s heartbeat check interval; confirm <section> briefly carries aria-busy="true"
  • Workflow list status counts: confirm aria-busy={countPoller.loading} is true during the initial fetch and polling refetch
  • axe-core: zero new violations on a page with a busy table
  • Regression: visual <ProgressBar> inside Table <thead> renders unchanged

References

🤖 Generated with Claude Code

A11y-Audit-Ref: 4.1.2-aria-busy-loading-regions

@vercel

vercel Bot commented Jun 12, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
holocene Ready Ready Preview, Comment Jul 6, 2026 4:36pm

Request Review

@github-actions github-actions Bot added a11y Accessibility audit PR a11y:no-fix-doc No A11y-Audit-Ref line; audit team triage labels Jun 12, 2026
@rosanusi rosanusi marked this pull request as ready for review June 12, 2026 14:20
@rosanusi rosanusi requested a review from a team as a code owner June 12, 2026 14:20
@github-actions github-actions Bot added a11y:bucket-3 Bucket 3: engineer required a11y:sc-4.1.2 and removed a11y:no-fix-doc No A11y-Audit-Ref line; audit team triage labels Jun 16, 2026
…essBar, Loading, and three polling consumers

Foundation primitives:
- Table: aria-busy="true" on the <table> element when the updating prop is true
- ProgressBar: role="progressbar" + aria-busy="true" on the meter div (the bar's
  presence already implies busy; the role and aria-busy make it programmatic)
- Loading: aria-busy="true" + aria-live="polite" on the skeleton container so AT
  announces the end of loading when the skeleton unmounts

Consumer wiring:
- workflow-run-layout: isPolling state flips true/false around the 10 s poll
  interval via queueMicrotask; the event-history slot wrapper carries aria-busy
- status-counts: aria-busy bound directly to countPoller.loading (already tracked)
- worker-details: isCheckingHeartbeat state flips around the staleness check
  interval; the worker-details section carries aria-busy

A11y-Audit-Ref: 4.1.2-aria-busy-loading-regions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@ardiewen

ardiewen commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@rosanusi Reviewed + adjusted so aria-busy/live semantics sit on the region that actually changes, not on indicators or layout wrappers.

Kept (real wired state): Table aria-busy={updating}, status-counts aria-busy={countPoller.loading}, worker-details aria-busy={refreshing}.

Reverted / fixed:

  • workflow-run-layout — dropped the isPolling/queueMicrotask flip (fake duration — true for one microtask) and its wrapper <div>, which collapsed the route's flex children into one and lost the parent gap-4. Event-history refresh is already covered by the Table's aria-busy.
  • progress-bar — reverted role="progressbar"/aria-busy: nameless + valueless = AT noise, and aria-busy on a childless indicator is inert. Follow-up DT-4214 to make it a proper widget.
  • loading — dropped inert aria-busy and the aria-live (won't fire on a text-less node inserted whole / removed); added role="status" + aria-label="Loading" and hid the decorative SVG.

Merged latest main (status-counts class conflict resolved). pnpm check clean.

@ardiewen ardiewen merged commit 7db61ab into main Jul 6, 2026
17 checks passed
@ardiewen ardiewen deleted the wcag/4.1.2-aria-busy-loading-regions branch July 6, 2026 17:02
temporal-cicd Bot pushed a commit that referenced this pull request Jul 8, 2026
Auto-generated version bump from 2.51.1 to 2.52.0

Bump type: minor

Changes included:
- [`9c6fcd54`](9c6fcd5) Add direct SSO redirect and backend logout (#3590)
- [`feab0d90`](feab0d9) a11y(4.1.3): Toaster role="log" → per-toast role="status"/"alert" for correct AT announcement semantics (#3560)
- [`d7bbfb01`](d7bbfb0) a11y(2.5.8): toast — replace bare close button with IconButton (36×36 px) (#3553)
- [`4efd6ab6`](4efd6ab) a11y(3.3.1): Holocene input primitives — add aria-invalid, aria-describedby, and uniform live-region error announcement (#3554)
- [`0600b700`](0600b70) Use green only (#3599)
- [`94107549`](9410754) Clarify activity pause timeout behavior (#3600)
- [`9f88d5a8`](9f88d5a) Bump node version to 22.23.1 or newer to fix issue from previous security release (#3604)
- [`ca4104ae`](ca4104a) Update reason copy and inputs (#3588)
- [`51db73fa`](51db73f) Update batch operation reason input hint (#3605)
- [`836d7c55`](836d7c5) a11y(2.4.3): route navigation — move focus to the main landmark on afterNavigate, not just scroll (#3538)
- [`4ee95696`](4ee9569) Improve re-renders for large encoded event histories (#3592)
- [`fa5e7aa1`](fa5e7aa) feature/schedules (#3603)
- [`0d9467fd`](0d9467f) Default includeHeartbeatDetails and includeLastFailure to true for getActivityExecution and pollActivityExecution (#3521)
- [`e5bc514e`](e5bc514) fix schedules: duplicate key (#3612)
- [`f1eb489f`](f1eb489) Remove preview badge (#3581)
- [`1e5173b4`](1e5173b) Add existing versions to worker create deployment version form (#3601)
- [`a8552bae`](a8552ba) fix schedules -e.trim not a function (#3613)
- [`0442f847`](0442f84) Fix width of ComputeBadge in VersionTableRow (#3615)
- [`ddbeb54f`](ddbeb54) fix(cloud-nav): animate and stabilize side-nav collapse (#3606)
- [`3cfc684b`](3cfc684) fix - schedules recent/upcoming runs - sort issue (#3616)
- [`92b8875b`](92b8875) Move timestamp out of translate (#3617)
- [`901258af`](901258a) Fix SAA and WF consistency (#3614)
- [`99593d97`](99593d9) DT-4001 - standalone nexus operations (#3496)
- [`f10d1bf1`](f10d1bf) Clamp codeblock to container width (#3621)
- [`0a9d93ce`](0a9d93c) Remove unnecessary bottom-0 (#3623)
- [`9dabb522`](9dabb52) chore(deps-dev): bump vite from 6.4.2 to 6.4.3 (#3610)
- [`5c1854d3`](5c1854d) News Feed (#3596)
- [`340da30f`](340da30) a11y(2.1.1): guard global r/R keydown so text inputs can receive the letter (#3589)
- [`dd97a9d1`](dd97a9d) fix(markdown-editor): disable chromatic snapshot for preview story (#3631)
- [`7db61ab9`](7db61ab) a11y(4.1.2): Table / ProgressBar / Loading primitives — expose aria-busy on data-refresh regions (#3555)
- [`d2111ecf`](d2111ec) a11y(4.1.3): Add live-region wrappers for workflow status, event count, filter counts, and Banner (#3561)
- [`24eabaec`](24eabae) a11y(2.4.6): guard DrawerContent against empty <h2> when title is omitted (#3595)
- [`3552e307`](3552e30) Fix CodeMirror Lezer dependency mismatch (#3632)
- [`7ac37199`](7ac3719) Update defaults to match workflow defaults (#3634)
- [`c1f02865`](c1f0286) Draft fix for link variant handling (#3620)
- [`bbbf2b8c`](bbbf2b8) Add connection status and optional Latest Version column to deployments (DT-4174) (#3618)
- [`76f266f4`](76f266f) DurationInput updates (#3633)
- [`07da53c5`](07da53c) COM-191 - prefill CloudFormation template params in Launch Stack link (#3619)
- [`90946e0b`](90946e0) Schedules - Timeout empty defaults (#3637)
- [`97f9ad39`](97f9ad3) fix(cloud-nav): smooth label fade on side-nav collapse/expand (#3628)
- [`a399ed35`](a399ed3) Improve Search Attribute deletion messaging (#3629)
- [`ad976d94`](ad976d9) Pass through source prop for News Feed Widget (#3638)
- [`6ef84fe3`](6ef84fe) Restrict select-all to exclude workflow status (#3639)
- [`4c3729f8`](4c3729f) Reduce news feed markdown whitespace (#3642)
- [`aa04a9b6`](aa04a9b) feat(nexus-operations): add loading state to standalone nexus operations list page header (#3643)
- [`dce2f804`](dce2f80) chore: remove unused generate-holocene-props script (#3644)
- [`760bc7bc`](760bc7b) Make megaphone icon bigger (#3645)
- [`c047384a`](c047384) refactor(nexus): replace hand-rolled types with @temporalio/proto (#3646)
rossedfort added a commit that referenced this pull request Jul 8, 2026
Auto-generated version bump from 2.51.1 to 2.52.0

Bump type: minor

Changes included:
- [`9c6fcd54`](9c6fcd5) Add direct SSO redirect and backend logout (#3590)
- [`feab0d90`](feab0d9) a11y(4.1.3): Toaster role="log" → per-toast role="status"/"alert" for correct AT announcement semantics (#3560)
- [`d7bbfb01`](d7bbfb0) a11y(2.5.8): toast — replace bare close button with IconButton (36×36 px) (#3553)
- [`4efd6ab6`](4efd6ab) a11y(3.3.1): Holocene input primitives — add aria-invalid, aria-describedby, and uniform live-region error announcement (#3554)
- [`0600b700`](0600b70) Use green only (#3599)
- [`94107549`](9410754) Clarify activity pause timeout behavior (#3600)
- [`9f88d5a8`](9f88d5a) Bump node version to 22.23.1 or newer to fix issue from previous security release (#3604)
- [`ca4104ae`](ca4104a) Update reason copy and inputs (#3588)
- [`51db73fa`](51db73f) Update batch operation reason input hint (#3605)
- [`836d7c55`](836d7c5) a11y(2.4.3): route navigation — move focus to the main landmark on afterNavigate, not just scroll (#3538)
- [`4ee95696`](4ee9569) Improve re-renders for large encoded event histories (#3592)
- [`fa5e7aa1`](fa5e7aa) feature/schedules (#3603)
- [`0d9467fd`](0d9467f) Default includeHeartbeatDetails and includeLastFailure to true for getActivityExecution and pollActivityExecution (#3521)
- [`e5bc514e`](e5bc514) fix schedules: duplicate key (#3612)
- [`f1eb489f`](f1eb489) Remove preview badge (#3581)
- [`1e5173b4`](1e5173b) Add existing versions to worker create deployment version form (#3601)
- [`a8552bae`](a8552ba) fix schedules -e.trim not a function (#3613)
- [`0442f847`](0442f84) Fix width of ComputeBadge in VersionTableRow (#3615)
- [`ddbeb54f`](ddbeb54) fix(cloud-nav): animate and stabilize side-nav collapse (#3606)
- [`3cfc684b`](3cfc684) fix - schedules recent/upcoming runs - sort issue (#3616)
- [`92b8875b`](92b8875) Move timestamp out of translate (#3617)
- [`901258af`](901258a) Fix SAA and WF consistency (#3614)
- [`99593d97`](99593d9) DT-4001 - standalone nexus operations (#3496)
- [`f10d1bf1`](f10d1bf) Clamp codeblock to container width (#3621)
- [`0a9d93ce`](0a9d93c) Remove unnecessary bottom-0 (#3623)
- [`9dabb522`](9dabb52) chore(deps-dev): bump vite from 6.4.2 to 6.4.3 (#3610)
- [`5c1854d3`](5c1854d) News Feed (#3596)
- [`340da30f`](340da30) a11y(2.1.1): guard global r/R keydown so text inputs can receive the letter (#3589)
- [`dd97a9d1`](dd97a9d) fix(markdown-editor): disable chromatic snapshot for preview story (#3631)
- [`7db61ab9`](7db61ab) a11y(4.1.2): Table / ProgressBar / Loading primitives — expose aria-busy on data-refresh regions (#3555)
- [`d2111ecf`](d2111ec) a11y(4.1.3): Add live-region wrappers for workflow status, event count, filter counts, and Banner (#3561)
- [`24eabaec`](24eabae) a11y(2.4.6): guard DrawerContent against empty <h2> when title is omitted (#3595)
- [`3552e307`](3552e30) Fix CodeMirror Lezer dependency mismatch (#3632)
- [`7ac37199`](7ac3719) Update defaults to match workflow defaults (#3634)
- [`c1f02865`](c1f0286) Draft fix for link variant handling (#3620)
- [`bbbf2b8c`](bbbf2b8) Add connection status and optional Latest Version column to deployments (DT-4174) (#3618)
- [`76f266f4`](76f266f) DurationInput updates (#3633)
- [`07da53c5`](07da53c) COM-191 - prefill CloudFormation template params in Launch Stack link (#3619)
- [`90946e0b`](90946e0) Schedules - Timeout empty defaults (#3637)
- [`97f9ad39`](97f9ad3) fix(cloud-nav): smooth label fade on side-nav collapse/expand (#3628)
- [`a399ed35`](a399ed3) Improve Search Attribute deletion messaging (#3629)
- [`ad976d94`](ad976d9) Pass through source prop for News Feed Widget (#3638)
- [`6ef84fe3`](6ef84fe) Restrict select-all to exclude workflow status (#3639)
- [`4c3729f8`](4c3729f) Reduce news feed markdown whitespace (#3642)
- [`aa04a9b6`](aa04a9b) feat(nexus-operations): add loading state to standalone nexus operations list page header (#3643)
- [`dce2f804`](dce2f80) chore: remove unused generate-holocene-props script (#3644)
- [`760bc7bc`](760bc7b) Make megaphone icon bigger (#3645)
- [`c047384a`](c047384) refactor(nexus): replace hand-rolled types with @temporalio/proto (#3646)

Co-authored-by: rossedfort <11775628+rossedfort@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a11y:bucket-3 Bucket 3: engineer required a11y:sc-4.1.2 a11y Accessibility audit PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants