Skip to content
Source
Sign inSign up

[Bug]: New project publishing toggle does not expose its state to screen readers #36082

Send to my agent
Closedcoygeek(GitHub profile, opens in a new tab) opened this issue 0 comments

Summary

In the command palette's New project flow, the Create private repository option changes whether the project is published, but its on/off state is absent from the option exposed to assistive technology. A focused Chromium browser test toggled the visual checkbox on and found no checked or pressed state on the option; the checkbox itself is hidden from the accessibility tree. The option should expose its current state before the user creates the project.

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/web

Steps to reproduce

  1. From a checkout of the commit below with dependencies installed, run the script with that checkout as its sole argument: sh repro.sh ./t3code.
  2. The script mounts the real command palette in its Chromium browser test with a mock connected environment and available GitHub account, opens Add Project → New project, enters a name, and clicks the publishing option twice.
  3. It checks that the visual checkbox changed on and off, confirms that aria-selected does not track either state, and checks whether the option exposes an on state through aria-checked or aria-pressed, or through a checkbox that is not hidden from assistive technology.

One run of the script reproduced the failure. Save the following as repro.sh; it requires the checkout's installed dependencies, vp, Python 3, Node.js, and the Chromium browser test runtime. It creates a uniquely named temporary test in the checkout and removes it on exit. Exit 0 with RESULT: expected behavior means the option or a visible checkbox exposes the on state, exit 1 with RESULT: defect reproduced means the visual state changed but the option did not expose it, and exit 2 means setup or the control failed.

Reproduction script: repro.sh
#!/bin/sh
set -u
repo=$1
scratch=$(mktemp -d)
test_file="$repo/apps/web/src/components/CommandPalette.y10-02.browser.test.tsx"
cleanup() {
  rm -f "$test_file"
  rm -rf "$scratch"
}
trap cleanup EXIT HUP INT TERM
printf 'vp version: '
vp --version
printf 'python3 version: '
python3 --version
printf 'node version: '
node --version
python3 - "$repo" "$test_file" <<'PY'
from pathlib import Path
import sys
repo = Path(sys.argv[1])
target = Path(sys.argv[2])
source = (repo / "apps/web/src/components/CommandPalette.composition.browser.test.tsx").read_text()
prelude = source.split("// The real palette and Base UI input must agree", 1)[0]
old = 'useEnvironmentQuery: () => ({ data: undefined, isLoading: false }),'
new = '''useEnvironmentQuery: () => ({ data: { versionControlSystems: [], sourceControlProviders: [{ kind: "github", label: "GitHub", status: "available", version: { _tag: "None" }, installHint: "Install GitHub CLI", detail: { _tag: "None" }, auth: { status: "authenticated", account: { _tag: "Some", value: "demo" }, host: { _tag: "None" }, detail: { _tag: "None" } } }] }, isLoading: false }),'''
if prelude.count(old) != 1:
    raise SystemExit("composition test mock changed")
prelude = prelude.replace(old, new)
test = """
it("exposes the new project publish toggle state", async () => {
  setup();
  await using _screen = await render(<CommandPalette>{null}</CommandPalette>);
  await act(() => openCommandPalette({ open: "add-project" }));
  await page.getByText("New project", { exact: true }).click();
  const input = page.getByRole("combobox");
  await input.fill("demo-project");
  const row = page.getByRole("option", { name: /Create private repository/ });
  await expect.element(row).toBeVisible();
  const checkbox = row.element().querySelector('[data-slot="checkbox"]');
  expect(checkbox).not.toBeNull();
  expect(checkbox?.hasAttribute("data-checked")).toBe(false);
  const selectedBefore = row.element().getAttribute("aria-selected");
  await row.click();
  await vi.waitFor(() => expect(checkbox?.hasAttribute("data-checked")).toBe(true));
  const selectedOn = row.element().getAttribute("aria-selected");
  const exposedState = row.element().getAttribute("aria-checked") ?? row.element().getAttribute("aria-pressed") ?? (checkbox?.getAttribute("aria-hidden") !== "true" ? checkbox?.getAttribute("aria-checked") : null);
  await row.click();
  await vi.waitFor(() => expect(checkbox?.hasAttribute("data-checked")).toBe(false));
  const selectedOff = row.element().getAttribute("aria-selected");
  console.log("CONTROL: publish visual state toggled on and off; aria-selected " + JSON.stringify([selectedBefore, selectedOn, selectedOff]));
  expect(exposedState).toBe("true");
});
"""
target.write_text(prelude + test)
PY
output="$scratch/output.txt"
(
  cd "$repo"
  vp test run apps/web/src/components/CommandPalette.y10-02.browser.test.tsx
) > "$output" 2>&1
status=$?
cat "$output"
if [ "$status" -eq 0 ]; then
  echo 'RESULT: expected behavior'
  exit 0
fi
if grep -q 'CONTROL: publish visual state toggled on and off' "$output" && grep -q 'expected null to be' "$output"; then
  echo 'RESULT: defect reproduced'
  exit 1
fi
echo 'RESULT: inconclusive'
exit 2

Expected behavior

The user guide says to "Turn on Create private repository on GitHub" to publish a new project (docs/user/source-control.md#L148-L155). In this flow, the option should expose whether publishing is currently on or off to assistive technology, so a screen-reader user can make that choice before creating the project.

Actual behavior

In the command palette, opening Add Project → New project with an available GitHub publishing target shows a "Create private repository on GitHub" option. Clicking it changes the nested checkbox from unchecked to checked, but the option has neither aria-checked nor aria-pressed afterwards, and the checkbox is aria-hidden="true". The focused browser test below reproduced this mismatch. The state controls whether creation passes a publishing target to the project operation (apps/web/src/components/CommandPalette.tsx#L2025-L2036).

Impact and scope

Impact: P2 - this is a consequential accessibility failure in an optional project creation setting: a screen-reader user cannot determine whether the creation action will also publish the repository. The script confirms the state is missing from the option after toggling; it does not exercise a specific screen reader.

The option appears only when a source-control publishing target is available (apps/web/src/components/CommandPalette.tsx#L2007-L2017, apps/web/src/components/CommandPalette.tsx#L2391-L2399). The initial state is off (apps/web/src/components/CommandPalette.tsx#L533); leaving it untouched safely creates a local-only project, while publishing later through Git actions is a possible workaround. The state mismatch was deterministic in the tested flow. Actual screen-reader announcements and other browser engines were not tested.

Earliest failure stage

Output or presentation.

Analysis or suspected cause

Source: The option renders a checkbox with aria-hidden and changes only newProjectPublishes when activated (apps/web/src/components/CommandPalette.tsx#L2399-L2432). The result row forwards its title and trailing content into CommandItem without passing a checked or pressed state (apps/web/src/components/CommandPaletteResults.tsx#L248-L295).

Additional context

The same hidden checkbox is present on the checked main revision 6790f85f53a060a3c322089c3fac5dfcecdfc8b1. Evidence provenance: observed in a focused Chromium browser test and supported by the linked source. Local verification: reproduced. Reproduction completeness: complete for the option's exposed checked state; actual screen-reader announcements and other browser engines were not tested. Restoration check: the script exits 0 only when the visual state toggles and the on state is exposed by the option or a checkbox visible to assistive technology.

Impact

Minor bug or occasional failure

Version or commit

main @ c00a373491

Environment

Chromium browser test on macOS arm64; Vite Plus 1.4.0; Vitest 5.0.5; Node.js 26.12.1.

Logs or stack traces

The focused test reached the option and toggled its visual state, then failed because the accessible checked or pressed state was absent:

CONTROL: publish visual state toggled on and off; aria-selected [null,null,null]
AssertionError: expected null to be 'true'
- Expected: "true"
+ Received: null
RESULT: defect reproduced

Screenshots, recordings, or supporting files

No response

Workaround

Leaving the option untouched creates a local-only project. Publishing later through Git actions is a possible workaround.

References

  • https://github.com/pingdotgg/t3code/issues/32566 — covers Tab navigation to project-flow submit buttons, not the publishing option's state.
  • https://github.com/pingdotgg/t3code/issues/32567 — covers announcement of submit shortcuts in project flows, not the publishing option's state.
  • https://github.com/pingdotgg/t3code/pull/33622 — proposes a different creation dialog and leaves repository publishing to Git actions; it does not change the current option's accessibility state.
  1. tanstack-source added labelsbug

  2. github-actions[bot](GitHub profile, opens in a new tab) added labelsvouch:denounced

  3. juliusmarminge closed this

Sign in to join this conversation.