Fix UI accessibility gaps and responsive report layout - #3
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Pull request overview
This PR addresses UI review findings by improving accessibility semantics (labels, alerts, live regions, and focus management) and fixing several responsive/layout issues across tool pages and reports, without changing scanner/API/security logic.
Changes:
- Add accessible names for form controls, improve error semantics (
role="alert"), and introduce stable live regions + focus-on-result for async tool result areas. - Improve responsive rendering of reports (CORS table horizontal scrolling, URL wrapping, badge wrapping) and adjust home grid columns for a 4-tool layout.
- Clean up styling tokens (contrast tweaks from
slate-500→slate-400, sticky header opacity) and remove unused Tailwind color entries / dead typography classes.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| tailwind.config.ts | Removes unused custom palette entries (ink.500, accent.600). |
| components/SeverityBadge.tsx | Marks decorative dot as aria-hidden for screen readers. |
| components/ScanReportView.tsx | Improves contrast, URL wrapping, and adds explicit “No findings.” empty state. |
| components/CorsReportView.tsx | Adds clearer Result labels, table caption/column scopes, and enforces min-width for horizontal scroll on small screens. |
| components/CertReportView.tsx | Improves contrast and wrapping behavior for target line and status badges. |
| app/tools/misconfig-mapper/View.tsx | Adds SR-only label + stable live region and focuses results heading on first result/error; prevents re-entrant submits while loading. |
| app/tools/jwt-inspector/View.tsx | Adds SR-only labels/IDs, proper alert/live semantics for async verify/crack, and prevents concurrent verify/crack actions. |
| app/tools/cors-tester/View.tsx | Adds SR-only label + stable live region and focuses results heading on first result/error; prevents re-entrant submits while loading. |
| app/tools/cert-viewer/View.tsx | Adds SR-only label + stable live region and focuses results heading on first result/error; prevents re-entrant scan/submit while loading. |
| app/page.tsx | Updates home grid breakpoint to avoid orphaned card layout with 4 tools. |
| app/layout.tsx | Improves header opacity, adds nav aria-label, and adjusts footer contrast color. |
| app/about/page.tsx | Removes unused prose classes (typography plugin not present) while retaining explicit styling. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Summary
Fixes the findings from a UI review of the running app. No scanner, API, or security logic is touched — this is UI-only.
The substantive part is accessibility: none of the six form controls had an accessible name (placeholders don't count), scan results were swapped in with no live region so a screen-reader user got silence for the whole 6-second round-trip, and errors rendered as plain text. Each server tool now wraps its result area in a stable live region that exists across both states, so the announcement actually fires:
with
aria-describedby={error ? "cert-error" : undefined}+aria-invalidon the input, and focus moving to the heading on the idle→result transition.The JWT Inspector deliberately gets neither of those. It has no submit action — decode runs synchronously on every keystroke — so a focus move would yank the caret out of the textarea mid-typing, and a live region around the decoded output would re-announce the entire subtree (both JSON panels, findings, verify and crack sections) on every character. It keeps only the parse-error alert and the three small async regions around verify/crack, which are real completions.
Layout fixes, all confirmed against the running app:
bg-ink-950/60, transparent enough that scrolled content ghosted through it on every page →/95.CorsReportView'soverflow-x-autonever engaged because the table had no min width, so at 375px it compressed to ~3 characters per line instead of scrolling →min-w-[760px].sm:grid-cols-2 lg:grid-cols-3with exactly four tools, orphaning the fourth card →sm:grid-cols-2 xl:grid-cols-4.titleon target URLs is invisible and unselectable on touch →break-all. Cert status badges now wrap.text-slate-500on real content computes to 4.21:1 onink-950, below AA; swapped toslate-400(7.81:1) wherever it carried content, left alone where decorative.Two behaviour fixes: the submit handlers guarded only via the disabled button, so a keyboard Enter could re-enter (and
onCrackawaited the wordlist fetch before setting its running flag, so rapid clicks started concurrent cracks); andCorsReportView's Result column rendered an em dash for every non-reflecting probe, which on a wildcard-CORS target meant eight rows of nothing — it now distinguishes wildcard / present / absent / error.Also:
about/page.tsxusedprose prose-invertbut@tailwindcss/typographywas never installed, so those classes were dead — removed rather than adding the dependency. Unusedink-500/accent-600dropped.Testing
npm run lint,npm run typecheck,npm test(39 passing), andnpm run buildall pass. Verified in-browser at 1280px and 375px: header no longer ghosts, four-card grid is balanced, CORS table scrolls rather than compressing, cert badges wrap, the Result column readsWildcard ACAOagainstapi.github.com, and typing a token into the JWT inspector keeps focus in the textarea.Link to Devin session: https://app.devin.ai/sessions/c13b64ef84ed489f8e564ba16c6ffe96
Requested by: @tinkthemaker