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(