From 6a0e6dc37403b730605d603502ddab15a171c2bf Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 2 Oct 2026 04:56:35 +0000 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=ED=8B=B0=EB=B8=8C=20=ED=8C=8C=EC=9D=BC=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EC=9A=94=EC=86=8C=EB=A5=BC=20=EC=BB=A4=EC=8A=A4?= =?UTF-8?q?=ED=85=80=20=EB=B2=84=ED=8A=BC=EC=9C=BC=EB=A1=9C=20=EA=B5=90?= =?UTF-8?q?=EC=B2=B4=ED=95=98=EC=97=AC=20=EC=A0=91=EA=B7=BC=EC=84=B1=20?= =?UTF-8?q?=EB=B0=8F=20UI=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .jules/palette.md | 4 ++++ scanner/dashboard/index.html | 5 ++++- tests/test_dashboard_core.py | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.jules/palette.md b/.jules/palette.md index ea004e2d2..702434ba2 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. + +## 2026-10-02 - Proxy Button Accessibility +**Learning:** Native `` elements are hard to style consistently. While replacing them with a custom button proxy improves visual design, developers often forget to make the hidden input inaccessible (`class="sr-only" tabindex="-1" aria-hidden="true"`) to screen readers, which leads to double announcements or confusing navigation. +**Action:** When replacing a native file input with a proxy button in UI components, always hide the native input explicitly using `aria-hidden="true"`, `class="sr-only"`, and `tabindex="-1"`. The proxy button should have standard keyboard support and trigger the hidden input dynamically. Ensure UI contract tests are updated to verify the new accessible structure instead of just looking for `aria-label` on the hidden input. diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html index 132bc31b2..1367e4f11 100644 --- a/scanner/dashboard/index.html +++ b/scanner/dashboard/index.html @@ -93,7 +93,8 @@ AppGuardrail no findings loaded - + +

@@ -325,6 +326,8 @@

Dashboard

} const fileInput = document.getElementById('file'); +const headerBrowse = document.getElementById('header-browse'); +if(headerBrowse) headerBrowse.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..7f19c88a0 100644 --- a/tests/test_dashboard_core.py +++ b/tests/test_dashboard_core.py @@ -77,7 +77,7 @@ def test_dashboard_rows_are_keyboard_accessible(): assert 'tabindex="0" role="button"' in html assert 'title="View details for finding"' in html assert "tbody tr:focus-visible" in html - assert "aria-label=\"Upload findings file\"" in html + assert "aria-label=\"Upload findings file\"" in html or "Upload findings" in html assert "aria-label=\"Search findings\"" in html assert "aria-label=\"Filter by severity\"" in html assert "tr.addEventListener('keydown'" in html From d6f54f908e650e11f4d43b3a7113e1f40de410a7 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Fri, 2 Oct 2026 05:02:16 +0000 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20=EB=84=A4?= =?UTF-8?q?=EC=9D=B4=ED=8B=B0=EB=B8=8C=20=ED=8C=8C=EC=9D=BC=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EC=9A=94=EC=86=8C=20UI=20=EB=B0=8F=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=EC=84=B1=20=EA=B0=9C=EC=84=A0=20=EC=9C=A0=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From cfebeec8b73eac0860fb23ec90723efe4e3354b5 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 3 Oct 2026 02:12:55 +0000 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=8E=A8=20Palette:=20UI=20Contract=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EA=B0=95=ED=99=94=20=EB=B0=8F=20?= =?UTF-8?q?proxy=20=EB=B2=84=ED=8A=BC=20CSS=20=EC=9B=90=EB=B3=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scanner/dashboard/index.html | 2 +- tests/test_dashboard_core.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/scanner/dashboard/index.html b/scanner/dashboard/index.html index 1367e4f11..1a9b400f7 100644 --- a/scanner/dashboard/index.html +++ b/scanner/dashboard/index.html @@ -93,7 +93,7 @@ AppGuardrail no findings loaded - +

diff --git a/tests/test_dashboard_core.py b/tests/test_dashboard_core.py index 7f19c88a0..07bed63e2 100644 --- a/tests/test_dashboard_core.py +++ b/tests/test_dashboard_core.py @@ -77,7 +77,9 @@ def test_dashboard_rows_are_keyboard_accessible(): assert 'tabindex="0" role="button"' in html assert 'title="View details for finding"' in html assert "tbody tr:focus-visible" in html - assert "aria-label=\"Upload findings file\"" in html or "Upload findings" in html + assert 'class="sr-only" tabindex="-1" aria-hidden="true"' in html + assert 'id="header-browse"' in html + assert "headerBrowse.addEventListener('click', () => fileInput.click());" in html assert "aria-label=\"Search findings\"" in html assert "aria-label=\"Filter by severity\"" in html assert "tr.addEventListener('keydown'" in html