From 382d340cdf15ea77f52bfcaf13d045cbd274afde Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 6 Sep 2026 13:55:00 +0000 Subject: [PATCH 1/5] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20ExportModal?= =?UTF-8?q?=EC=9D=98=20=EC=A0=91=EA=B7=BC=20=EA=B6=8C=ED=95=9C=20=EC=95=88?= =?UTF-8?q?=EB=82=B4=20=ED=88=B4=ED=8C=81=20=EC=A0=91=EA=B7=BC=EC=84=B1=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 비활성화된 "접근 관리" 버튼에 aria-describedby로 안내 텍스트가 연결되어 있었으나, native disabled 속성으로 인해 키보드 포커스를 받지 못해 스크린 리더 사용자가 해당 안내를 인지할 수 없는 문제가 있었습니다. native disabled를 aria-disabled={true}로 변경하고, onClick에서 이벤트를 차단하여 키보드 포커스가 가능하도록 개선했습니다. CSS 및 테스트 코드도 이에 맞게 수정했습니다. --- .jules/palette.md | 3 +++ frontend/src/components/modals/ExportModal.test.tsx | 4 +++- frontend/src/components/modals/ExportModal.tsx | 3 ++- frontend/src/styles.css | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index bd0f73248..44054ea60 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -57,3 +57,6 @@ ## 2026-07-30 - Add window.confirm for destructive actions **Learning:** Destructive actions like deleting groups and edge relationships previously occurred immediately without user confirmation. **Action:** Always wrap delete operations with window.confirm() dialogs and ensure corresponding tests successfully mock window.confirm. +## 2023-10-27 - Disabled Button Accessibility with Tooltips +**Learning:** Native `disabled` attributes on buttons prevent them from receiving keyboard focus. If a disabled button relies on a tooltip or `aria-describedby` hint (e.g., explaining *why* it is disabled, like missing permissions), screen reader users navigating by keyboard will never discover the hint because the button is skipped in the tab order. +**Action:** When a disabled button has an explanatory hint, do not use the native `disabled` attribute. Instead, use `aria-disabled="true"`, apply disabled visual styles using CSS attribute selectors (e.g., `button[aria-disabled="true"]`), and manually prevent the action in the `onClick` handler (`e.preventDefault()`). This keeps the button in the focus order so assistive technologies can read the hint, while still semantically and functionally disabling it. diff --git a/frontend/src/components/modals/ExportModal.test.tsx b/frontend/src/components/modals/ExportModal.test.tsx index bd89c5384..2b27d8f9c 100644 --- a/frontend/src/components/modals/ExportModal.test.tsx +++ b/frontend/src/components/modals/ExportModal.test.tsx @@ -176,7 +176,9 @@ describe('ExportModal', () => { expect(screen.getByText('접근 권한 관리는 프로젝트 권한 설정에서 처리합니다.')).toBeInTheDocument(); const accessManagementButton = screen.getByRole('button', { name: '접근 관리' }); - expect(accessManagementButton).toBeDisabled(); + expect(accessManagementButton).toHaveAttribute('aria-disabled', 'true'); + accessManagementButton.focus(); + expect(accessManagementButton).toHaveFocus(); expect(accessManagementButton).toHaveAttribute('aria-describedby', 'share-export-access-hint'); expect(accessManagementButton).not.toHaveAttribute('title'); }); diff --git a/frontend/src/components/modals/ExportModal.tsx b/frontend/src/components/modals/ExportModal.tsx index 995393ceb..9ccda8ad9 100644 --- a/frontend/src/components/modals/ExportModal.tsx +++ b/frontend/src/components/modals/ExportModal.tsx @@ -202,7 +202,8 @@ export function ExportModal({ )}