Skip to content

[Website] Keep autosave progress out of live announcements - #3817

Merged
adamziel merged 1 commit into
trunkfrom
codex/autosave-status-progressbar
Jul 15, 2026
Merged

[Website] Keep autosave progress out of live announcements#3817
adamziel merged 1 commit into
trunkfrom
codex/autosave-status-progressbar

Conversation

@ashfame

@ashfame ashfame commented Jun 21, 2026

Copy link
Copy Markdown
Member

Why

The save indicator used role="status" while changing its percentage for every
OPFS 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 progressbar with an exact
aria-valuenow. Keep a separate, stable status region for completion and
failure 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=static
  • npm exec nx -- run playground-website:typecheck --output-style=static
  • npm exec nx -- run playground-website:lint --output-style=static
  • npm exec nx -- run playground-website:e2e:playwright --args='--project=chromium --grep="should create and finish autosaving a Playground from the root URL"' --output-style=static
  • npm exec nx -- run playground-website:e2e:playwright --args='--project=chromium --grep="should treat New Playground as an explicit fresh start"' --output-style=static
@adamziel
adamziel force-pushed the codex/autosave-status-progressbar branch from 7a5e291 to 82ad5c7 Compare July 15, 2026 09:50
@adamziel adamziel changed the title [codex] Use progressbar for autosave progress Jul 15, 2026
@adamziel
adamziel marked this pull request as ready for review July 15, 2026 10:11
@adamziel
adamziel requested review from a team, bgrgicak and Copilot July 15, 2026 10:11
@adamziel
adamziel merged commit d1adae0 into trunk Jul 15, 2026
56 checks passed
@adamziel
adamziel deleted the codex/autosave-status-progressbar branch July 15, 2026 10:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-live role="progressbar" exposing aria-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')
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment