🎨 Palette: [UX improvement] Make UploadResumeModal fully accessible#477
🎨 Palette: [UX improvement] Make UploadResumeModal fully accessible#477aafre wants to merge 1 commit into
Conversation
- Add `role="dialog"`, `aria-modal="true"`, and `aria-labelledby` to modal container for screen readers. - Hide file input with `sr-only peer` (instead of `hidden`) to keep it in the DOM keyboard navigation tab order. - Add visible focus rings `peer-focus-visible:ring-2` to the file upload label wrapper for clear keyboard indications. - Add `aria-label` and visible focus outlines to the modal close button. - Document custom file input accessibility approach in `.Jules/palette.md`. Co-authored-by: aafre <8656674+aafre@users.noreply.github.com>
|
👋 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 New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
There was a problem hiding this comment.
Code Review
This pull request enhances the accessibility of the UploadResumeModal by adding ARIA attributes, improving keyboard navigation for file uploads, and updating the project's accessibility documentation. The changes include replacing hidden file inputs with screen-reader-only elements and adding focus-visible styles. Feedback identifies a missing focus trap in the modal and suggests using peer-disabled modifiers for the file input label to correctly represent the disabled state, as standard disabled pseudo-classes are ineffective on labels.
| role="dialog" | ||
| aria-modal="true" | ||
| aria-labelledby="upload-modal-title" |
There was a problem hiding this comment.
While adding ARIA roles and labels is a significant improvement for screen reader support, this modal is missing a focus trap. According to the general rules, all modals must implement a focus trap to ensure keyboard focus remains within the modal's focusable elements while it is open. This is critical for accessibility, especially when aria-modal="true" is used, as it prevents users from accidentally tabbing out of the modal into the background content.
References
- For accessibility, all modals must implement a focus trap to ensure keyboard focus remains within the modal's focusable elements while it is open.
| <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" |
There was a problem hiding this comment.
The disabled:opacity-50 utility does not work on a element because labels do not support the :disabled pseudo-class. Since the associated input is a peer, you should use peer-disabled:opacity-50 to visually indicate the disabled state (e.g., when parsing is true). Additionally, adding peer-disabled:cursor-not-allowed improves the UX by providing clear feedback that the action is unavailable.
| 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" |
|
|
||
| ## 2025-02-14 - Custom File Input Keyboard Accessibility | ||
| **Learning:** Using `display: none` or Tailwind's `hidden` on a `<input type="file">` element completely removes it from the browser's accessibility tree and keyboard tab order, breaking keyboard navigation for file uploads. | ||
| **Action:** When styling custom file inputs, always place the `<input type="file">` before the visual `<label>` wrapper in the DOM, style it with `sr-only peer` to keep it focusable but visually hidden, and add `peer-focus-visible` styling (like `peer-focus-visible:ring-2`) to the subsequent `<label>` to visually indicate keyboard focus. |
There was a problem hiding this comment.
Consider updating this action item to include the peer-disabled pattern. When styling custom file inputs where a label acts as the visual trigger, the label must reflect the input's disabled state (e.g., during file processing) to provide a consistent UX, as standard disabled: modifiers are ineffective on labels.
| **Action:** When styling custom file inputs, always place the `<input type="file">` before the visual `<label>` wrapper in the DOM, style it with `sr-only peer` to keep it focusable but visually hidden, and add `peer-focus-visible` styling (like `peer-focus-visible:ring-2`) to the subsequent `<label>` to visually indicate keyboard focus. | |
| Action: When styling custom file inputs, always place the <input type="file"> before the visual <label> wrapper in the DOM, style it with sr-only peer to keep it focusable but visually hidden. Add peer-focus-visible styling (like peer-focus-visible:ring-2) and peer-disabled styling (like peer-disabled:opacity-50 peer-disabled:cursor-not-allowed) to the subsequent <label> to ensure the visual state correctly reflects the input's focus and disabled states. |
References
- Ensure documentation, such as testing plans, is updated to reflect UI and implementation changes made in the same pull request.
|
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. |
💡 What
This PR updates the
UploadResumeModalcomponent to significantly improve its keyboard and screen-reader accessibility.🎯 Why
Custom styled file uploads (which hide the original
input type="file") often break keyboard navigation if they are completely hidden from the DOM (e.g., viadisplay: noneor Tailwind'shidden). Users navigating by keyboard cannot "tab" to the input to trigger the file dialog. Furthermore, the modal lacked appropriate semanticdialogroles and ARIA labels.♿ Accessibility
role="dialog",aria-modal="true", andaria-labelledbyto properly announce the modal to screen readers.hiddenclass from the file<input>and appliedsr-only peer, keeping the element visually hidden but explicitly within the keyboard tab sequence.peer-focus-visibleclasses to the "Choose File" label, creating a clear blue focus ring when a user tabs into the hidden file input.aria-label="Close dialog"to the close iconbutton, and added high-contrastfocus-visiblestyling for keyboard navigation..Jules/palette.mdto ensure this accessible custom file input pattern is standardized across the codebase.PR created automatically by Jules for task 2822450963525978763 started by @aafre