Give the terminal and Add Project buttons a reason a screen reader can hear
Secret Scan / scan (push) Successful in 10s
Build App (Preview) / compute-version (pull_request) Successful in 6s
Secret Scan / scan (pull_request) Successful in 10s
Build App (Preview) / create-release (pull_request) Successful in 3s
Build App (Preview) / build-macos (pull_request) Successful in 2m41s
Build App (Preview) / build-windows (pull_request) Successful in 4m56s
Build App (Preview) / build-linux (pull_request) Successful in 6m47s
Build App (Preview) / prune-previews (pull_request) Successful in 1s

Both were the defect the new hook exists for. The sidebar's Claude terminal
button is disabled whenever the container is not running and never said so —
its `title` names the action, so the precondition appeared nowhere in the
accessibility tree at all. Add Project's submit button is disabled while an
add is in flight, and its only signal is the label swapping to "Adding…" on
an element a screen reader can no longer reach.

The submit button needs a second guard the hook cannot supply: Enter inside
a text field submits a form without touching the submit button, so
`handleSubmit` now returns early while loading. Without it, swapping
`disabled` for `aria-disabled` would have turned an accessibility fix into a
double-submit bug.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011YPqHpjV4EL6RNEwrRKqQm
This commit is contained in:
2026-09-02 09:08:57 -07:00
co-authored by Claude Opus 5
parent aa0a574091
commit 1eb91a35eb
4 changed files with 185 additions and 13 deletions
@@ -55,6 +55,10 @@ export default function AddProjectDialog({ onClose }: Props) {
const handleSubmit = async (e?: React.FormEvent) => {
if (e) e.preventDefault();
// The submit button is `aria-disabled` rather than `disabled` while an add
// is in flight, and Enter inside a text field submits the form without
// touching the button at all. Both routes end here, so the guard does too.
if (loading) return;
if (!name.trim()) {
setError("Project name is required");
return;
@@ -97,7 +101,19 @@ export default function AddProjectDialog({ onClose }: Props) {
<Button size="md" variant="ghost" onClick={onClose}>
Cancel
</Button>
<Button size="md" variant="primary" type="submit" form={formId} disabled={loading}>
<Button
size="md"
variant="primary"
type="submit"
form={formId}
unavailable={loading}
unavailableReason="The project is being added. Wait for it to finish."
title={
loading
? "The project is being added. Wait for it to finish."
: undefined
}
>
{loading ? "Adding…" : "Add Project"}
</Button>
</>