Skip to content

🎨 Palette: Improve accessibility with ARIA labels for icon-only buttons#530

Open
ngoiyaeric wants to merge 1 commit intomainfrom
palette-accessibility-improvement-7996752336833846116
Open

🎨 Palette: Improve accessibility with ARIA labels for icon-only buttons#530
ngoiyaeric wants to merge 1 commit intomainfrom
palette-accessibility-improvement-7996752336833846116

Conversation

@ngoiyaeric
Copy link
Collaborator

@ngoiyaeric ngoiyaeric commented Feb 18, 2026

I have implemented a series of micro-UX improvements focused on accessibility (a11y) by adding aria-label attributes to icon-only buttons and inputs throughout the application.

💡 What

  • Added aria-label to buttons in components/header.tsx (history, calendar, usage).
  • Added aria-label to buttons in components/mobile-icons-bar.tsx (new chat, profile, map, calendar, search, upgrade, attachment, submit).
  • Added aria-label to buttons in components/chat-panel.tsx (new chat, attachment, clear attachment).
  • Added aria-label to the submit button in components/followup-panel.tsx.
  • Added aria-label to the toggle button in components/history.tsx.
  • Added aria-label to the search button in components/header-search-button.tsx.
  • Added aria-label to navigation and action buttons in components/calendar-notepad.tsx.
  • Added aria-label to the textarea in components/calendar-notepad.tsx.

🎯 Why

Icon-only buttons are often inaccessible to screen readers as they lack text content. By adding aria-label, we ensure that users relying on assistive technologies can understand the purpose and action of each button.

♿ Accessibility

This change specifically targets WCAG guidelines for accessible names and roles, making the core functionality of the application more inclusive.

✅ Verification

Verified the presence and visibility of these labels using a Playwright script and captured screenshots of the UI.


PR created automatically by Jules for task 7996752336833846116 started by @ngoiyaeric

Summary by CodeRabbit

  • Accessibility

    • Improved screen reader support and assistive technology compatibility by adding descriptive labels to interactive elements throughout the application, including navigation buttons, forms, and action controls.
  • Documentation

    • Added accessibility best practices documentation for icon-only buttons.

This commit adds `aria-label` attributes to various icon-only buttons across the application to improve accessibility for screen reader users. Components updated include Header, MobileIconsBar, ChatPanel, FollowupPanel, History, HeaderSearchButton, and CalendarNotepad.

Key improvements:
- Added descriptive labels to navigation and action buttons.
- Ensured all icon-only buttons provide contextual information to assistive technologies.
- Added a label to the note textarea in the calendar notepad.
- Verified changes with Playwright screenshots.

Co-authored-by: ngoiyaeric <115367894+ngoiyaeric@users.noreply.github.com>
@vercel
Copy link
Contributor

vercel bot commented Feb 18, 2026

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

Project Deployment Actions Updated (UTC)
qcx Ready Ready Preview, Comment Feb 18, 2026 9:56am

@google-labs-jules
Copy link
Contributor

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 18, 2026

Walkthrough

The PR adds ARIA accessibility labels to interactive UI elements across multiple components without changing behavior or logic. Components updated include calendar-notepad, chat-panel, followup-panel, header-search-button, header, history, and mobile-icons-bar, plus accessibility guidance documentation.

Changes

Cohort / File(s) Summary
Accessibility Documentation
.jules/palette.md
Added documentation entry (2025-05-15) describing accessibility guidance for icon-only buttons, recommending aria-label or sr-only spans instead of relying on title attributes.
Interactive Components
components/calendar-notepad.tsx, components/chat-panel.tsx, components/followup-panel.tsx, components/header-search-button.tsx, components/header.tsx, components/history.tsx, components/mobile-icons-bar.tsx
Added aria-label attributes to icon buttons and interactive elements (e.g., "Toggle history", "New chat", "Open calendar", "Attach file", "Send message") across navigation, chat, calendar, and mobile UI components. No functional or control-flow changes; attributes enable proper assistive technology identification.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Suggested labels

Review effort 2/5

Poem

🐰 With whiskers twitching in delight,
I hop through code from left to right,
Adding labels bright and clear,
So screen readers all can hear!
Aria-blessed, our buttons sing,
Accessibility's a wondrous thing! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding ARIA labels to icon-only buttons for accessibility improvements across multiple components.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch palette-accessibility-improvement-7996752336833846116

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.

Copy link

@charliecreates charliecreates bot left a comment

Choose a reason for hiding this comment

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

Overall the change is a clear a11y improvement by providing accessible names for icon-only controls. The main follow-ups are about consistency and specificity: ensure labels are unique where multiple similar controls exist, keep title and aria-label text aligned when both are present, and prefer label/aria-labelledby for form fields when feasible to reduce future drift. No functional issues are evident in the diff.

Additional notes (3)
  • Readability | components/header.tsx:55-61
    aria-label="Toggle history" is used both here and in components/history.tsx, but this button is specifically tied to the logo interaction (data-testid="logo-history-toggle"). Consider a more specific accessible name so screen reader users can distinguish it from other history toggles (especially if both can appear in the accessibility tree in different layouts).

  • Readability | components/header.tsx:80-87
    The button uses title="Open Calendar" and aria-label="Open calendar". Having both is fine, but they should ideally match exactly to avoid inconsistent announcements/tooltips and to reduce translation/i18n drift (if applicable).

  • Maintainability | components/calendar-notepad.tsx:131-131
    The textarea now has aria-label="Add a note" while also having a descriptive placeholder. That’s good for accessible naming, but if you also render a visible label elsewhere in the component (not shown in diff), aria-label would override it and can cause duplication/mismatched names. Prefer aria-labelledby when there is (or could be) a visible label element.

Summary of changes

Summary

This PR improves accessibility across the UI by adding explicit accessible names to icon-only controls.

Key updates

  • Added aria-label attributes to multiple icon-only Button/button elements in:
    • components/header.tsx (history toggle, calendar, usage)
    • components/mobile-icons-bar.tsx (new chat, calendar, search, upgrade, attachment, submit)
    • components/chat-panel.tsx (new chat, attachment, clear attachment)
    • components/followup-panel.tsx (submit)
    • components/history.tsx (toggle)
    • components/header-search-button.tsx (analyze/search action)
    • components/calendar-notepad.tsx (prev/next week, tag location, fly-to location, and textarea)

Documentation

  • Added .jules/palette.md entry capturing the a11y learning/action standard for icon-only buttons.

Comment on lines 51 to 55
<a href="https://buy.stripe.com/14A3cv7K72TR3go14Nasg02" target="_blank" rel="noopener noreferrer">
<Button variant="ghost" size="icon">
<Button variant="ghost" size="icon" aria-label="Upgrade">
<TentTree className="h-[1.2rem] w-[1.2rem] transition-all rotate-0 scale-100" />
</Button>
</a>

Choose a reason for hiding this comment

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

For links that wrap an icon-only button, the accessible name should ideally be on the interactive element that receives focus/activation. Depending on the underlying Button implementation, focus may land on the <a> rather than the inner control, and the label on the inner button may not be used.

Consider moving the accessible name to the anchor (or ensuring the anchor is the only interactive element) to avoid nested interactive semantics and to guarantee the label is announced correctly.

Suggestion

Avoid nested interactive controls and place the label on the element that actually receives focus:

<a
  href="..."
  target="_blank"
  rel="noopener noreferrer"
  aria-label="Upgrade"
  className="inline-flex"
>
  <TentTree ... />
</a>

Alternatively, use your Button component’s asChild pattern (if available) so the anchor is the rendered element while keeping button styling. Reply with "@CharlieHelps yes please" if you want me to prepare a commit applying this pattern here.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
components/chat-panel.tsx (1)

219-232: ⚠️ Potential issue | 🟡 Minor

Test selector mismatch prevents desktop attachment button interactions in tests.

The desktop attachment button has data-testid="desktop-attachment-button", but tests target [data-testid="attachment-button"] (chat.spec.ts, responsive.spec.ts, images.spec.ts). No component carries the generic "attachment-button" ID—only the prefixed variants exist ("desktop-attachment-button" and "mobile-attachment-button"). Tests will silently fail to interact with the attachment buttons because the selector cannot be found.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/chat-panel.tsx` around lines 219 - 232, The test selector mismatch
arises because the desktop attachment Button (in the JSX block rendering
Paperclip) uses data-testid="desktop-attachment-button" while tests look for
"attachment-button"; update the component so the Button rendered when !isMobile
includes the generic data-testid="attachment-button" (you may keep
"desktop-attachment-button" as an additional attribute if desired) so tests that
query "[data-testid='attachment-button']" can find and interact with the desktop
attachment button; ensure this change is applied to the Button that calls
handleAttachmentClick (and mirror for the mobile variant if present).
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be08900 and e3cd742.

📒 Files selected for processing (8)
  • .jules/palette.md
  • components/calendar-notepad.tsx
  • components/chat-panel.tsx
  • components/followup-panel.tsx
  • components/header-search-button.tsx
  • components/header.tsx
  • components/history.tsx
  • components/mobile-icons-bar.tsx
🧰 Additional context used
🧬 Code graph analysis (3)
components/calendar-notepad.tsx (1)
tests/calendar.spec.ts (1)
  • test (3-154)
components/chat-panel.tsx (1)
tests/chat.spec.ts (2)
  • testInfo (64-77)
  • test (4-89)
components/mobile-icons-bar.tsx (3)
components/profile-toggle.tsx (1)
  • ProfileToggle (9-82)
components/map-toggle.tsx (1)
  • MapToggle (14-39)
components/chat.tsx (1)
  • Chat (29-216)
🪛 markdownlint-cli2 (0.21.0)
.jules/palette.md

[warning] 1-1: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🔇 Additional comments (13)
components/history.tsx (1)

22-22: LGTM. The label accurately reflects the toggle semantics regardless of which icon variant is rendered.

components/followup-panel.tsx (1)

62-62: LGTM. Label is descriptive and consistent with the equivalent button label in chat-panel.tsx.

components/chat-panel.tsx (2)

178-185: LGTM. New chat button label is correct and consistent with mobile-icons-bar.tsx.


298-303: LGTM. Clear attachment label is descriptive and aligned with the existing data-testid.

components/header-search-button.tsx (1)

150-165: LGTM. aria-label provides the accessible name for the icon-only desktop button; the coexisting title still serves as a hover tooltip for mouse users without conflict.

components/calendar-notepad.tsx (3)

97-103: LGTM. Navigation labels are clear and follow the Previous/Next week week-navigation convention.


136-152: LGTM. aria-label="Add a note" gives the textarea a concise accessible name, and aria-label="Tag current location" correctly describes the icon-only MapPin action.


167-173: LGTM. "Fly to tagged location" is descriptive and distinct from the "Tag current location" label applied to the textarea's MapPin button.

components/mobile-icons-bar.tsx (2)

40-41: LGTM. New chat label is consistent with the desktop equivalent.


56-61: LGTM. Attach file and Send message labels are correct and match chat-panel equivalents.

components/header.tsx (3)

80-89: LGTM. Calendar toggle label is consistent with mobile-icons-bar.tsx.


93-117: LGTM. Usage toggle is correctly labeled in both desktop and mobile slots; the mobile and desktop buttons are mutually exclusive via hidden md:flex / flex md:hidden, so there is no duplicate-label issue.


55-69: The duplicate aria-label="Toggle history" accessibility issue does not exist; only the logo button is ever visible.

The HistoryContainer at line 104 is placed inside <div className="flex-1 hidden md:flex ..."> (shown at md+ breakpoints) but internally wraps its content with <div className="sm:hidden block"> (hidden at md+ breakpoints). This means the History component is never actually rendered to users at any screen size due to the conflicting visibility classes. Only the logo button (lines 55–69) with aria-label="Toggle history" remains visible and accessible. There is no duplicate button to differentiate.

However, the HistoryContainer placement inside the desktop-only container combined with its own mobile-only visibility class suggests dead code or a configuration error that should be clarified.

Likely an incorrect or invalid review comment.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.jules/palette.md:
- Around line 1-3: Change the level-2 heading to a top-level heading and add a
blank line after it to satisfy MD041 and MD022: replace "## 2025-05-15 -
[Accessibility: Icon-Only Button Labels]" with a single leading '#' heading and
insert an empty line immediately after that heading so the file starts with a
top-level heading and a following blank line.

In `@components/mobile-icons-bar.tsx`:
- Around line 48-50: The Search Button (Button with
data-testid="mobile-search-button" and aria-label="Search") is labeled but has
no onClick handler, causing a silent failure for screen-reader users; either
wire this Button to the correct click action (add the onClick handler that
triggers the mobile search flow) or mark it as non-interactive until implemented
(add disabled={true} and ensure aria-disabled="true") and keep the aria-label;
update the Button in components/mobile-icons-bar.tsx accordingly so the
accessible state matches functionality.

---

Outside diff comments:
In `@components/chat-panel.tsx`:
- Around line 219-232: The test selector mismatch arises because the desktop
attachment Button (in the JSX block rendering Paperclip) uses
data-testid="desktop-attachment-button" while tests look for
"attachment-button"; update the component so the Button rendered when !isMobile
includes the generic data-testid="attachment-button" (you may keep
"desktop-attachment-button" as an additional attribute if desired) so tests that
query "[data-testid='attachment-button']" can find and interact with the desktop
attachment button; ensure this change is applied to the Button that calls
handleAttachmentClick (and mirror for the mobile variant if present).

Comment on lines +1 to +3
## 2025-05-15 - [Accessibility: Icon-Only Button Labels]
**Learning:** Icon-only buttons without explicit `aria-label` attributes are inaccessible to screen reader users, as they often lack descriptive text content. While `title` attributes provide some information on hover, they are not a substitute for `aria-label` in terms of accessibility standards.
**Action:** Always ensure icon-only buttons have an `aria-label` or an `sr-only` span describing their action. This project now consistently uses `aria-label` for common interface actions like toggling history, opening calendars, and submitting forms.
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix markdown heading level and missing blank line (MD041, MD022).

The file opens with a level-2 heading (##) — MD041 requires the first line of a file to be a top-level heading (#). MD022 also requires a blank line after the heading.

📝 Proposed fix
-## 2025-05-15 - [Accessibility: Icon-Only Button Labels]
+# 2025-05-15 - [Accessibility: Icon-Only Button Labels]
+
 **Learning:** Icon-only buttons without explicit `aria-label` attributes...
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## 2025-05-15 - [Accessibility: Icon-Only Button Labels]
**Learning:** Icon-only buttons without explicit `aria-label` attributes are inaccessible to screen reader users, as they often lack descriptive text content. While `title` attributes provide some information on hover, they are not a substitute for `aria-label` in terms of accessibility standards.
**Action:** Always ensure icon-only buttons have an `aria-label` or an `sr-only` span describing their action. This project now consistently uses `aria-label` for common interface actions like toggling history, opening calendars, and submitting forms.
# 2025-05-15 - [Accessibility: Icon-Only Button Labels]
**Learning:** Icon-only buttons without explicit `aria-label` attributes are inaccessible to screen reader users, as they often lack descriptive text content. While `title` attributes provide some information on hover, they are not a substitute for `aria-label` in terms of accessibility standards.
**Action:** Always ensure icon-only buttons have an `aria-label` or an `sr-only` span describing their action. This project now consistently uses `aria-label` for common interface actions like toggling history, opening calendars, and submitting forms.
🧰 Tools
🪛 markdownlint-cli2 (0.21.0)

[warning] 1-1: Headings should be surrounded by blank lines
Expected: 1; Actual: 0; Below

(MD022, blanks-around-headings)


[warning] 1-1: First line in a file should be a top-level heading

(MD041, first-line-heading, first-line-h1)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.jules/palette.md around lines 1 - 3, Change the level-2 heading to a
top-level heading and add a blank line after it to satisfy MD041 and MD022:
replace "## 2025-05-15 - [Accessibility: Icon-Only Button Labels]" with a single
leading '#' heading and insert an empty line immediately after that heading so
the file starts with a top-level heading and a following blank line.

Comment on lines +48 to 50
<Button variant="ghost" size="icon" data-testid="mobile-search-button" aria-label="Search">
<Search className="h-[1.2rem] w-[1.2rem] transition-all rotate-0 scale-100" />
</Button>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Labeled but non-functional button worsens screen reader UX.

The Search button has aria-label="Search" but no onClick handler. Before this change the unlabeled icon was unlikely to be interacted with by assistive technology users. Adding a label now makes it fully discoverable, so screen reader users will attempt to activate it and receive no response — a silent failure. Either wire up the handler or add disabled until the feature is implemented.

🛡️ Minimal fix until onClick is available
-      <Button variant="ghost" size="icon" data-testid="mobile-search-button" aria-label="Search">
+      <Button variant="ghost" size="icon" data-testid="mobile-search-button" aria-label="Search" disabled>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@components/mobile-icons-bar.tsx` around lines 48 - 50, The Search Button
(Button with data-testid="mobile-search-button" and aria-label="Search") is
labeled but has no onClick handler, causing a silent failure for screen-reader
users; either wire this Button to the correct click action (add the onClick
handler that triggers the mobile search flow) or mark it as non-interactive
until implemented (add disabled={true} and ensure aria-disabled="true") and keep
the aria-label; update the Button in components/mobile-icons-bar.tsx accordingly
so the accessible state matches functionality.

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.

2 participants

Comments