Skip to content

🎨 Palette: [Make UploadResumeModal accessible for keyboard users]#442

Closed
aafre wants to merge 1 commit into
mainfrom
palette-upload-modal-accessibility-13164399205075021548
Closed

🎨 Palette: [Make UploadResumeModal accessible for keyboard users]#442
aafre wants to merge 1 commit into
mainfrom
palette-upload-modal-accessibility-13164399205075021548

Conversation

@aafre
Copy link
Copy Markdown
Owner

@aafre aafre commented Apr 3, 2026

🎨 Palette: [Make UploadResumeModal accessible for keyboard users]

What

This PR comprehensively upgrades the accessibility of the UploadResumeModal.tsx component. Specifically:

  • Adds correct semantic ARIA attributes to the modal container.
  • Makes the hidden file upload input accessible to keyboard-only and screen-reader users by utilizing the sr-only peer pattern.
  • Ensures all interactive buttons inside the modal (close, cancel, continue, and the file upload label) clearly display a visual focus ring when navigated via keyboard.

Why

Previously, the <input type="file"> was visually styled away using the hidden class. Because hidden maps to display: none, it was completely stripped from the browser's accessibility tree, making it impossible to upload a file without a mouse. Also, the lack of role="dialog" or clear focus rings on modal buttons provided a poor experience for keyboard navigators.

Accessibility Improvements

  • ✅ Screen reader support via role="dialog" and aria-modal="true".
  • ✅ File input is now fully tab-navigable using the sr-only utility rather than hidden.
  • ✅ Focus is now visually obvious on all buttons via focus-visible Tailwind classes.
  • ✅ Icon-only close button now has an explicit aria-label.

PR created automatically by Jules for task 13164399205075021548 started by @aafre

- Added `role="dialog"`, `aria-modal="true"`, and `aria-labelledby` to modal container
- Added focus visibility classes and ARIA labels to close button
- Transformed hidden file input to use `sr-only peer` pattern for keyboard accessibility
- Ensured label visually responds to focus state
- Added explicit focus styles for cancel and continue buttons

Co-authored-by: aafre <8656674+aafre@users.noreply.github.com>
@google-labs-jules
Copy link
Copy Markdown
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.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request improves the accessibility of the UploadResumeModal by adding ARIA roles, modal attributes, and focus indicators for interactive elements. It also updates the project's learning log with new guidelines for accessible file inputs and modals. Feedback was provided to ensure documentation history is preserved by appending new entries rather than overwriting existing ones, and to fix a styling issue where the disabled state of the file input label was not correctly applied using standard utility classes.

Comment thread .Jules/palette.md
Comment on lines +1 to +3
## 2024-04-03 - Accessible File Inputs and Modals
**Learning:** Custom file inputs that use `display: none` or Tailwind's `hidden` are completely removed from the accessibility tree and keyboard tab order, breaking usability for screen readers and keyboard users. Additionally, custom modal implementations often lack critical accessibility roles (`dialog`, `aria-modal`) and explicit focus indicators for interaction elements.
**Action:** Always use the `sr-only peer` pattern on `<input type="file">` instead of `hidden`, and style the associated `<label>` with `peer-focus-visible` classes to maintain focus visibility while hiding the ugly default file input visually. Ensure all custom modals receive `role="dialog"`, `aria-modal="true"`, and proper `aria-labelledby` IDs, along with clear focus rings on all interactive buttons (including icon-only close buttons).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The new accessibility guidelines are a valuable addition to the project's learning log. However, they should be appended as a new entry rather than replacing the existing entry for 'ResponsiveConfirmDialog'. Overwriting previous entries removes established project standards and history from the documentation. Please preserve both entries.

Suggested change
## 2024-04-03 - Accessible File Inputs and Modals
**Learning:** Custom file inputs that use `display: none` or Tailwind's `hidden` are completely removed from the accessibility tree and keyboard tab order, breaking usability for screen readers and keyboard users. Additionally, custom modal implementations often lack critical accessibility roles (`dialog`, `aria-modal`) and explicit focus indicators for interaction elements.
**Action:** Always use the `sr-only peer` pattern on `<input type="file">` instead of `hidden`, and style the associated `<label>` with `peer-focus-visible` classes to maintain focus visibility while hiding the ugly default file input visually. Ensure all custom modals receive `role="dialog"`, `aria-modal="true"`, and proper `aria-labelledby` IDs, along with clear focus rings on all interactive buttons (including icon-only close buttons).
## 2025-02-14 - ResponsiveConfirmDialog for Destructive Actions
**Learning:** Destructive actions (like Delete) implemented with custom hardcoded modals lack standard accessibility attributes (role="dialog", aria-modal, etc.) and mobile responsiveness (like bottom sheets). This app has a ResponsiveConfirmDialog component designed specifically for this purpose, but it was not being utilized uniformly.
**Action:** Always use ResponsiveConfirmDialog for destructive confirmation prompts (such as DeleteResumeModal) to ensure a consistent, accessible, and mobile-friendly UX that prevents accidental data loss.
## 2024-04-03 - Accessible File Inputs and Modals
**Learning:** Custom file inputs that use display: none or Tailwind's hidden are completely removed from the accessibility tree and keyboard tab order, breaking usability for screen readers and keyboard users. Additionally, custom modal implementations often lack critical accessibility roles (dialog, aria-modal) and explicit focus indicators for interaction elements.
**Action:** Always use the sr-only peer pattern on <input type="file"> instead of hidden, and style the associated <label> with peer-focus-visible classes to maintain focus visibility while hiding the ugly default file input visually. Ensure all custom modals receive role="dialog", aria-modal="true", and proper aria-labelledby IDs, along with clear focus rings on all interactive buttons (including icon-only close buttons).
References
  1. Ensure documentation, such as testing plans, is updated to reflect UI and implementation changes made in the same pull request.

<label
htmlFor="resume-file-input"
className="btn-primary inline-flex items-center gap-2 px-6 py-3 cursor-pointer disabled:opacity-50"
className="btn-primary inline-flex items-center gap-2 px-6 py-3 cursor-pointer disabled:opacity-50 peer-focus-visible:ring-2 peer-focus-visible:ring-accent peer-focus-visible:ring-offset-2"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The disabled:opacity-50 utility does not work on elements because they do not support the :disabled pseudo-class. Since this label is associated with a 'peer' input that is disabled during the parsing state, you should use peer-disabled utilities to correctly reflect the disabled state visually and update the cursor.

Suggested change
className="btn-primary inline-flex items-center gap-2 px-6 py-3 cursor-pointer disabled:opacity-50 peer-focus-visible:ring-2 peer-focus-visible:ring-accent peer-focus-visible:ring-offset-2"
className="btn-primary inline-flex items-center gap-2 px-6 py-3 cursor-pointer peer-disabled:opacity-50 peer-disabled:cursor-not-allowed peer-focus-visible:ring-2 peer-focus-visible:ring-accent peer-focus-visible:ring-offset-2"

aafre added a commit that referenced this pull request Apr 11, 2026
Add role="dialog", aria-modal, aria-labelledby to modal container.
Add aria-label and focus-visible ring to close button.
Convert hidden file input to sr-only peer with peer-focus-visible.
Add focus-visible rings to Cancel and Continue buttons.

Cherry-picked from Jules PR #442.
aafre added a commit that referenced this pull request Apr 11, 2026
Add tests for all 10 cherry-picked Jules PRs:
- keywordMatcher: subsumption logic with Map optimization (#456)
- StorageLimitModal: dialog semantics + focus rings (#449)
- IconManager: sr-only file input + clear button a11y (#434)
- SectionEditor: button aria-labels + focus rings (#414)
- UploadResumeModal: dialog semantics + keyboard a11y (#442)
- ResumeCard: action button focus rings (#420)
- ResponsiveConfirmDialog: focus states (#399, test from PR)

135 tests total, all passing.
@aafre
Copy link
Copy Markdown
Owner Author

aafre commented May 25, 2026

Closing duplicate — the most recent version of this change is PR #537.

@aafre aafre closed this May 25, 2026
@google-labs-jules
Copy link
Copy Markdown
Contributor

Closing duplicate — the most recent version of this change is PR #537.

Understood. Acknowledging that this work is now obsolete and stopping work on this task.

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