Skip to content

fix(a11y): add accessible labels to unlabeled form controls - #23

Merged
AndersonDesign1 merged 1 commit into
mainfrom
chore/a11y-control-labels
Jun 22, 2026
Merged

fix(a11y): add accessible labels to unlabeled form controls#23
AndersonDesign1 merged 1 commit into
mainfrom
chore/a11y-control-labels

Conversation

@AndersonDesign1

Copy link
Copy Markdown
Owner

What

Adds aria-label to five form controls flagged by React Doctor's accessibility pass whose only "label" was a placeholder (which is not an accessible name) or a hidden file input with no name:

  • project collaboration composer <textarea>
  • portal project message composer <textarea>
  • clients search <input>
  • project files + portal files hidden upload <input>s

Skipped (false positives)

  • client-access-dialog.tsx:20 — the trigger <button> already gets its accessible name from projected "Are you a client?" text (base-ui render prop the analyzer didn't trace).
  • onboarding-form.tsx:128 — the slug input already has an associated <FieldLabel htmlFor="slug">.

Notes

Part of the focused React Doctor follow-up. We deliberately did not commit a doctor.config.ts (it would flip CI to full-lint mode); these are genuine, low-risk a11y wins worth doing on their own merit. typecheck + lint pass locally.

🤖 Generated with Claude Code

React Doctor's accessibility pass flagged form controls whose only
"label" was a placeholder (not an accessible name) or a hidden file input
with no name. Add aria-label to the five genuine cases:

- project collaboration composer textarea
- portal project message composer textarea
- clients search input
- project files + portal files hidden upload inputs

Skipped two false positives: the client-access dialog button already gets
its name from projected text, and the onboarding slug input already has an
associated <FieldLabel htmlFor>.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clientra Ready Ready Preview, Comment Jun 22, 2026 3:32pm

@coderabbitai

coderabbitai Bot commented Jun 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@AndersonDesign1, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 18 minutes and 48 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 97744303-cbf5-4bfe-8dfe-2e0b3b22f3de

📥 Commits

Reviewing files that changed from the base of the PR and between a36b5a3 and 1f0aa5f.

📒 Files selected for processing (5)
  • src/components/projects/project-collaboration-panel.tsx
  • src/components/projects/project-files-panel.tsx
  • src/routes/clients/index.tsx
  • src/routes/portal/files.tsx
  • src/routes/portal/projects/$id.tsx
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/a11y-control-labels

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

React Doctor found no issues. 🎉

Reviewed by React Doctor for commit 1f0aa5f.

@greptile-apps

greptile-apps Bot commented Jun 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds aria-label attributes to five unlabeled form controls identified by a React Doctor accessibility pass, addressing the gap where placeholder text was the only label (which is not a valid accessible name).

  • Three controls (two textareas, one search input) receive a genuinely effective aria-label that will be announced by screen readers.
  • Two hidden file <input> elements receive aria-label, but because they use Tailwind's hidden class (display: none) they are removed from the accessibility tree — the label is silently ignored by assistive technology. The accessible name for those upload actions belongs on the visible trigger buttons instead.

Confidence Score: 4/5

Safe to merge; all changes are additive attribute additions with no runtime behaviour impact.

The three textarea and search-input fixes are correct and improve accessibility as intended. The two aria-label additions on display:none file inputs do not achieve their stated goal — those attributes are invisible to assistive technology — so the a11y improvement for the file-upload controls is incomplete, though harmless.

src/components/projects/project-files-panel.tsx and src/routes/portal/files.tsx — the aria-label on their hidden file inputs has no effect; the accessible name should be on the triggering buttons.

Important Files Changed

Filename Overview
src/components/projects/project-collaboration-panel.tsx Adds aria-label to the project collaboration textarea — correct and effective fix.
src/components/projects/project-files-panel.tsx Adds aria-label to a display:none hidden file input — the attribute is stripped from the accessibility tree and provides no actual a11y benefit.
src/routes/clients/index.tsx Adds aria-label to the clients search input — correct and effective fix.
src/routes/portal/files.tsx Adds aria-label to a display:none hidden file input — same no-op issue as project-files-panel.tsx.
src/routes/portal/projects/$id.tsx Adds aria-label to the portal project message composer textarea — correct and effective fix.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Form Control] --> B{Visible in accessibility tree?}
    B -- Yes / display:block --> C[aria-label applied and announced ✅]
    B -- No / display:none --> D[Removed from a11y tree, aria-label ignored ⚠️]

    C --> E[project-collaboration textarea]
    C --> F[portal project textarea]
    C --> G[clients search input]

    D --> H[project-files-panel hidden file input]
    D --> I[portal/files hidden file input]

    H --> J[Trigger button has visible text 'Choose Files' — accessible ✅]
    I --> K[Drop-zone button has visual content — accessible ✅]
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[Form Control] --> B{Visible in accessibility tree?}
    B -- Yes / display:block --> C[aria-label applied and announced ✅]
    B -- No / display:none --> D[Removed from a11y tree, aria-label ignored ⚠️]

    C --> E[project-collaboration textarea]
    C --> F[portal project textarea]
    C --> G[clients search input]

    D --> H[project-files-panel hidden file input]
    D --> I[portal/files hidden file input]

    H --> J[Trigger button has visible text 'Choose Files' — accessible ✅]
    I --> K[Drop-zone button has visual content — accessible ✅]
Loading

Comments Outside Diff (1)

  1. src/components/projects/project-files-panel.tsx, line 218-228 (link)

    P2 aria-label on a display:none element is a no-op

    Tailwind's hidden utility maps to display: none, which removes the element from the accessibility tree entirely — so the aria-label added here (and likewise in src/routes/portal/files.tsx) is never surfaced to a screen reader. The real accessible name for the upload action needs to live on the triggering button that calls inputRef.current?.click(). Both triggering buttons already have visible text ("Choose Files" / the drop-zone button), so this is harmless, but the stated a11y goal is not achieved for the file-upload controls.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/components/projects/project-files-panel.tsx
    Line: 218-228
    
    Comment:
    **`aria-label` on a `display:none` element is a no-op**
    
    Tailwind's `hidden` utility maps to `display: none`, which removes the element from the accessibility tree entirely — so the `aria-label` added here (and likewise in `src/routes/portal/files.tsx`) is never surfaced to a screen reader. The real accessible name for the upload action needs to live on the **triggering button** that calls `inputRef.current?.click()`. Both triggering buttons already have visible text ("Choose Files" / the drop-zone button), so this is harmless, but the stated a11y goal is not achieved for the file-upload controls.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
src/components/projects/project-files-panel.tsx:218-228
**`aria-label` on a `display:none` element is a no-op**

Tailwind's `hidden` utility maps to `display: none`, which removes the element from the accessibility tree entirely — so the `aria-label` added here (and likewise in `src/routes/portal/files.tsx`) is never surfaced to a screen reader. The real accessible name for the upload action needs to live on the **triggering button** that calls `inputRef.current?.click()`. Both triggering buttons already have visible text ("Choose Files" / the drop-zone button), so this is harmless, but the stated a11y goal is not achieved for the file-upload controls.

Reviews (1): Last reviewed commit: "fix(a11y): add accessible labels to unla..." | Re-trigger Greptile

@AndersonDesign1
AndersonDesign1 merged commit 4574fc5 into main Jun 22, 2026
8 checks passed
@AndersonDesign1
AndersonDesign1 deleted the chore/a11y-control-labels branch June 22, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant