spb/ultra-sharp-agent-skills Public
Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.
Python 100%
1<!--2Author: Simon-Pierre Boucher3Contact: contact@spboucher.ai4-->56# Accessibility Patterns — Copy-Paste Reference78## Contents9- Skip link10- Focus styles11- Accessible form field with error12- Icon-only button13- Live regions (async updates)14- Accessible modal dialog15- Reduced motion16- Contrast tokens17- Gotchas1819## Skip link2021First focusable element on the page; visible only on focus.2223```html24<a class="skip-link" href="#main">Skip to main content</a>25<main id="main" tabindex="-1">…</main>26```2728```css29.skip-link {30 position: absolute;31 left: -9999px;32}33.skip-link:focus {34 left: 8px;35 top: 8px;36 z-index: 100;37}38```3940## Focus styles4142`:focus-visible` shows the ring for keyboard users without flashing it on every mouse click.4344```css45:focus-visible {46 outline: 2px solid var(--color-focus, #1a56db);47 outline-offset: 2px;48}49/* never do: :focus { outline: none; } without a replacement */50```5152## Accessible form field with error5354```html55<label for="email">Email address</label>56<input id="email" name="email" type="email" autocomplete="email"57 aria-describedby="email-error" aria-invalid="true">58<p id="email-error" class="error">Enter an email address with an @, like name@example.com.</p>59```6061Remove `aria-invalid` and the error node (or empty it) once the field validates.6263## Icon-only button6465```html66<button type="button" aria-label="Close dialog">67 <svg aria-hidden="true" focusable="false">…</svg>68</button>69```7071`aria-hidden` on the SVG keeps screen readers from announcing the icon twice.7273## Live regions (async updates)7475```html76<!-- polite: status updates, search-result counts -->77<div aria-live="polite" class="visually-hidden" id="status"></div>7879<!-- assertive, errors only -->80<div role="alert" id="form-alert"></div>81```8283```js84document.getElementById('status').textContent = '12 results found';85```8687The live region must exist in the DOM before you write into it — injecting a new `aria-live` node with text is not announced reliably.8889## Accessible modal dialog9091Native `<dialog>` gives focus trapping and Esc for free — prefer it.9293```html94<dialog id="confirm" aria-labelledby="confirm-title">95 <h2 id="confirm-title">Delete file?</h2>96 <button type="button" id="cancel">Cancel</button>97 <button type="button" id="ok">Delete</button>98</dialog>99```100101```js102const dlg = document.getElementById('confirm');103dlg.showModal(); // traps focus, Esc closes104dlg.addEventListener('close', () => opener.focus()); // return focus to the trigger105```106107## Reduced motion108109```css110@media (prefers-reduced-motion: reduce) {111 *, *::before, *::after {112 animation-duration: 0.01ms !important;113 animation-iteration-count: 1 !important;114 transition-duration: 0.01ms !important;115 scroll-behavior: auto !important;116 }117}118```119120## Contrast tokens121122Bake compliance into tokens so components can't ship a failing pair.123124```css125:root {126 --text-on-light: #1f2937; /* 14.7:1 on #ffffff */127 --text-muted: #4b5563; /* 7.6:1 on #ffffff — still AA for body text */128 --color-focus: #1a56db; /* 3.6:1 vs #ffffff — passes 3:1 UI minimum */129}130```131132Check ratios with a tool (e.g., `npx wcag-contrast 4b5563 ffffff`) rather than by eye.133134## Gotchas135136- `display: none` and `visibility: hidden` hide content from screen readers too; use a `.visually-hidden` clip-pattern class for screen-reader-only text.137- `tabindex` values >0 break natural focus order — only ever use `0` and `-1`.138- `role="button"` on a div does NOT add Enter/Space handling; you must write the keydown handler yourself (another reason to use `<button>`).139- Placeholder text is not a label and usually fails contrast; see designing-forms.140- `aria-label` overrides visible text — if a button says "Save" but `aria-label="Submit"`, voice-control users saying "click Save" fail (WCAG 2.5.3 label-in-name).141- Automated tools (axe, Lighthouse) catch roughly a third of WCAG issues; the keyboard and screen-reader walkthroughs are not optional.142