[Website] Keep autosave progress out of live announcements - #3817
Merged
Conversation
adamziel
force-pushed
the
codex/autosave-status-progressbar
branch
from
July 15, 2026 09:50
7a5e291 to
82ad5c7
Compare
adamziel
marked this pull request as ready for review
July 15, 2026 10:11
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR updates the Playground website’s save indicator accessibility behavior to prevent screen readers from continuously announcing autosave progress, while still providing completion and failure announcements.
Changes:
- Replaces the live
role="status"progress updates with a non-liverole="progressbar"exposingaria-valuenow. - Adds a dedicated, stable live region for completion/failure announcements and resets it on sync start / Playground switches.
- Updates Playwright E2E assertions to validate the new progressbar + announcement behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/playground/website/src/components/browser-chrome/save-status-indicator.tsx | Splits progress vs. result announcements by introducing a progressbar for in-flight sync and a separate status live region for completion/failure. |
| packages/playground/website/playwright/e2e/website-ui.spec.ts | Adjusts E2E sampling/assertions to validate progressbar semantics and stable completion/failure announcements. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
184
to
202
| const progress = | ||
| opfsSync?.status === 'syncing' ? opfsSync.progress : undefined; | ||
| const progressPercent = getProgressPercent(progress); | ||
| return ( | ||
| const syncLabel = getSyncLabel({ site: activeSite, opfsSync }); | ||
| // A progressbar exposes exact progress when a screen reader user | ||
| // navigates to it without broadcasting every file-count update. | ||
| return withStatusAnnouncement( | ||
| <div | ||
| className={classNames(css.indicator, css.saving)} | ||
| aria-label={`${getSyncLabel({ | ||
| site: activeSite, | ||
| opfsSync, | ||
| })} ${progressPercent}%`} | ||
| role="status" | ||
| aria-label={ | ||
| syncOperation === 'autosave' | ||
| ? 'Autosave progress' | ||
| : 'Save progress' | ||
| } | ||
| aria-valuemax={100} | ||
| aria-valuemin={0} | ||
| aria-valuenow={progressPercent} | ||
| role="progressbar" | ||
| > |
Comment on lines
+285
to
+291
| function SaveStatusAnnouncement({ announcement }: { announcement: string }) { | ||
| return ( | ||
| <div className="sr-only" role="status"> | ||
| {announcement} | ||
| </div> | ||
| ); | ||
| } |
Comment on lines
+385
to
+396
| function getSyncOperation({ | ||
| site, | ||
| opfsSync, | ||
| }: { | ||
| site: SiteInfo | undefined; | ||
| opfsSync: OpfsSync | undefined; | ||
| }): SyncOperation { | ||
| return ( | ||
| opfsSync?.operation ?? | ||
| (site && isAutosavedSite(site) ? 'autosave' : 'save') | ||
| ); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The save indicator used
role="status"while changing its percentage for everyOPFS file. Because that role is a polite, atomic live region, screen readers
announced the entire label continuously during autosave.
What changed
Expose in-progress saves as a non-live
progressbarwith an exactaria-valuenow. Keep a separate, stablestatusregion for completion andfailure only. Clear that result when a new sync starts, announce failures only
when entering the error state, and suppress stale completion announcements when
switching Playgrounds.
The inline comments document why progress and result announcements are separate
and why the transition state is reset at those lifecycle boundaries.
Closes #3815.
Validation
npm exec nx -- run playground-website:test --output-style=staticnpm exec nx -- run playground-website:typecheck --output-style=staticnpm exec nx -- run playground-website:lint --output-style=staticnpm exec nx -- run playground-website:e2e:playwright --args='--project=chromium --grep="should create and finish autosaving a Playground from the root URL"' --output-style=staticnpm exec nx -- run playground-website:e2e:playwright --args='--project=chromium --grep="should treat New Playground as an explicit fresh start"' --output-style=static