diff --git a/.jules/palette.md b/.jules/palette.md index ea004e2d2..29dbeddeb 100644 --- a/.jules/palette.md +++ b/.jules/palette.md @@ -81,3 +81,7 @@ ## 2026-08-12 - Skip to Content Accessibility **Learning:** Screen reader and keyboard-only users experience significant friction when forced to navigate through repetitive header controls on every page load. **Action:** Keep a visible-on-focus skip link as the first interactive element, target a programmatically focusable main container, and give the focused link a high-contrast outline. + +## 2023-10-27 - 파일 업로드 버튼 접근성 개선 +**Learning:** `aria-hidden="true"`는 파일 입력 요소를 접근성 트리에서 제거하여 스크린 리더에서 읽히지 않도록 합니다. 네이티브 input[type="file"]을 커스텀 버튼으로 교체할 때, 네이티브 요소를 완전히 숨기고 커스텀 버튼이 포커스를 받도록 보장해야 합니다. +**Action:** 접근성 개선을 위해 네이티브 요소에 `aria-hidden="true"`, `tabindex="-1"`, `class="sr-only"`를 적용하고 이를 트리거하는 프록시 버튼을 사용합니다. diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html index 132bc31b2..b213e626c 100644 --- a/scanner/dashboard/index.html +++ b/scanner/dashboard/index.html @@ -93,7 +93,8 @@ AppGuardrail no findings loaded - + +

@@ -325,6 +326,9 @@

Dashboard

} const fileInput = document.getElementById('file'); +const fileProxy = document.getElementById('file-proxy'); +fileProxy.addEventListener('click', () => fileInput.click()); + fileInput.addEventListener('change', () => { const selectedFile = fileInput.files?.[0]; fileInput.value = ''; diff --git a/tests/test_dashboard_core.py b/tests/test_dashboard_core.py index 75a5809f8..1711372b2 100644 --- a/tests/test_dashboard_core.py +++ b/tests/test_dashboard_core.py @@ -302,3 +302,20 @@ def test_dashboard_search_escape_clears_input(): assert "e.key === 'Escape'" in html assert "query = '';" in html assert "render();" in html + + +def test_file_upload_proxy_accessibility_contract(): + """File upload must use an accessible proxy button instead of native file input.""" + html = dashboard_index_path().read_text(encoding="utf-8") + assert 'class="sr-only"' in html and 'tabindex="-1"' in html and 'aria-hidden="true"' in html and ' fileInput.click())" in html + + +def test_file_upload_proxy_accessibility_contract_is_documented_accurately(): + """UX accessibility learnings must be properly documented in the journal.""" + import pathlib + journal_path = pathlib.Path(__file__).parent.parent / ".jules" / "palette.md" + if journal_path.exists(): + journal_text = journal_path.read_text(encoding="utf-8") + assert '`aria-hidden="true"`는 파일 입력 요소를 접근성 트리에서 제거' in journal_text