[Bug]: New project publishing toggle does not expose its state to screen readers #36082
Send to my agentSummary#
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#
- From a checkout of the commit below with dependencies installed, run the script with that checkout as its sole argument:
sh repro.sh ./t3code. - 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.
- It checks that the visual checkbox changed on and off, confirms that
aria-selecteddoes not track either state, and checks whether the option exposes an on state througharia-checkedoraria-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.
tanstack-source added labelsbug
github-actions[bot](GitHub profile, opens in a new tab) added labelsvouch:denounced
juliusmarminge closed this
Sign in to join this conversation.