From 17735eb8c8650585a679bdef3491a50f1dd6c43f Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Thu, 30 Jul 2026 13:58:56 +0000 Subject: [PATCH] Hi! Jules here. I've successfully implemented the UX and accessibility updates you requested. Here is a breakdown of the changes I made: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ๐ŸŽจ Palette: [UX improvement] Add accessible disabled states to form buttons ๐Ÿ’ก What: - Removed native `disabled` attributes from the primary form buttons in `AddTableModal` and `GroupModal`. - Added `aria-disabled` and `title` attributes for tooltips on disabled buttons. - Added explicit `onClick` handlers to prevent form processing when the button is visually disabled. - Updated visual styling to replicate the disabled state (`opacity: 0.5, cursor: "not-allowed"`). - Updated corresponding test assertions in `ModalCoverage.test.tsx` to check `aria-disabled`. ๐ŸŽฏ Why: Native `disabled` buttons are removed from the browser's tab order, making them invisible to screen readers and preventing users from discovering why the button is disabled via tooltips. Using `aria-disabled` solves this, but requires manual intervention to block the actions. ๐Ÿ“ธ Before/After: Before: `disabled` attribute used. Tooltips wouldn't show. After: `aria-disabled` used with custom styles and `onClick` handlers. Tooltips appear on hover/focus. โ™ฟ Accessibility: Screen readers now announce the buttons as disabled, and keyboard-only users can tab to the buttons to read the tooltips explaining the required actions. Let me know if you need any further adjustments! --- .jules/palette.md | 3 +++ frontend/src/components/modals/AddTableModal.tsx | 10 ++++++---- frontend/src/components/modals/GroupModal.tsx | 5 ++++- frontend/src/components/modals/ModalCoverage.test.tsx | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index d892e2f96..816c3dd8b 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -54,3 +54,6 @@ ## 2024-07-13 - [Table Node Accessibility] **Learning:** Adding `aria-hidden="true"` inside `abbr` elements with `aria-label` prevents screen readers from redundantly announcing short abbreviations like "PK" or "NN" along with their full label. **Action:** When creating short, domain-specific abbreviations with tooltips, use `aria-label` on the wrapper and hide the visual text from screen readers using `aria-hidden="true"` to create a cleaner auditory experience. +## 2024-05-18 - [Add aria-disabled and tooltip to disabled buttons] +**Learning:** In React, replacing the native `disabled` attribute with `aria-disabled="true"` correctly announces the disabled state to screen readers and keeps the element focusable to display tooltips on hover/focus. However, unlike native `disabled`, `aria-disabled` does not block click events or form submissions. For form submit buttons, when the native `disabled` attribute is removed, pressing "Enter" in an input field will trigger a form submission. +**Action:** When converting a button to use `aria-disabled`, you must explicitly intercept the click/submit action by adding an `onClick` handler that calls `e.preventDefault()` when the button is logically disabled (e.g., `onClick={(e) => { if (!isValid) e.preventDefault(); }}`). diff --git a/frontend/src/components/modals/AddTableModal.tsx b/frontend/src/components/modals/AddTableModal.tsx index 024bde03f..004bd80f0 100644 --- a/frontend/src/components/modals/AddTableModal.tsx +++ b/frontend/src/components/modals/AddTableModal.tsx @@ -78,11 +78,13 @@ export function AddTableModal({ diff --git a/frontend/src/components/modals/ModalCoverage.test.tsx b/frontend/src/components/modals/ModalCoverage.test.tsx index aa9dac53a..2f7ee8400 100644 --- a/frontend/src/components/modals/ModalCoverage.test.tsx +++ b/frontend/src/components/modals/ModalCoverage.test.tsx @@ -83,7 +83,7 @@ describe('modal behavior coverage', () => { ) fireEvent.submit(screen.getByRole('dialog')) expect(onSubmit).toHaveBeenCalledOnce() - expect(screen.getByRole('button', { name: '์ €์žฅ' })).toBeEnabled() + expect(screen.getByRole('button', { name: '์ €์žฅ' })).toHaveAttribute('aria-disabled', 'false') }) it('covers EditEdgeModal visibility and actions', () => { @@ -242,7 +242,7 @@ describe('modal behavior coverage', () => { />, ) expect(screen.getByText('๋“ฑ๋ก๋œ ๊ทธ๋ฃน์ด ์—†์Šต๋‹ˆ๋‹ค.')).toBeInTheDocument() - expect(screen.getByRole('button', { name: '์ถ”๊ฐ€' })).toBeDisabled() + expect(screen.getByRole('button', { name: '์ถ”๊ฐ€' })).toHaveAttribute('aria-disabled', 'true') rerender(