More accessible components
Copy-paste HTML + CSS recipes for accessible alerts, breadcrumbs, cards, sidebars, hero sections, menus, and text areas. Each pattern includes the markup, styles, and the WCAG criteria it satisfies. All meet WCAG 2.2 AAA on contrast and target size — adapt the colors to your brand while preserving ratios.
Alert
Status message users may need to notice. role="status" for polite, role="alert" for assertive.
- Use role="status" (polite) for non-urgent updates; role="alert" (assertive) only for errors that need immediate attention.
- Don't rely on color alone — include an icon or text prefix (e.g., 'Error:').
- Text must meet AAA contrast (7:1 normal, 4.5:1 large) on the alert background.
<div class="alert alert--success" role="status">
<strong>Success</strong>
<p>Your changes have been saved.</p>
</div>.alert {
display: flex;
flex-direction: column;
gap: 0.25rem;
padding: 1rem;
border-radius: 8px;
border-left: 4px solid var(--accent);
background: color-mix(in oklch, var(--accent) 10%, white);
color: #1a1a1a;
}
.alert--success { --accent: oklch(52% 0.17 145); }
.alert--error { --accent: oklch(55% 0.20 27); }
.alert--info { --accent: oklch(55% 0.19 245); }
.alert strong { color: var(--accent); }Card
Linked content container. The entire card is clickable but only the link element is focusable.
- Make the whole card clickable by absolutely-positioning the link to cover it, but keep only the link in the tab order.
- Card heading should be an <h2> or <h3> appropriate to the page outline.
- Don't disable focus outline — extend it to wrap the whole card so keyboard users see a clear target.
<article class="card-component">
<h3>
<a href="/article/">Card title</a>
</h3>
<p>Short description that summarises the linked content.</p>
</article>.card-component {
position: relative;
padding: 1.25rem;
border-radius: 10px;
border: 1px solid #d0d0d8;
background: white;
transition: background 0.15s;
}
.card-component:hover { background: #f5f3ff; }
.card-component h3 { margin: 0 0 0.5rem; }
.card-component a::after {
content: "";
position: absolute;
inset: 0;
border-radius: 10px;
}
.card-component a:focus-visible::after {
outline: 3px solid #5b21b6;
outline-offset: 2px;
}Hero
Top-of-page introduction. <h1> first, single CTA, decorative graphic marked aria-hidden.
- Exactly one <h1> per page — make it the hero title.
- Decorative images use alt="" and aria-hidden="true".
- Call-to-action button must have 4.5:1 contrast in both themes (AAA).
<section class="hero">
<img src="/hero.svg" alt="" aria-hidden="true" width="120" height="120">
<div>
<h1>Accessibility, plainly</h1>
<p>Open AI for WCAG 2.2 AAA — built for neurodivergent communities.</p>
<a class="hero-cta" href="/about/">Learn more</a>
</div>
</section>.hero {
display: flex;
gap: 1.5rem;
align-items: center;
padding: 2rem;
border-radius: 12px;
background: linear-gradient(135deg, #ede9fe, #dbeafe, #d1fae5);
border-left: 4px solid #5b21b6;
}
.hero h1 { margin: 0 0 0.5rem; color: #1a1a1a; }
.hero p { margin: 0 0 1rem; color: #1a1a1a; }
.hero-cta {
display: inline-block;
padding: 0.625rem 1.25rem;
background: #4c1d95;
color: white;
border-radius: 6px;
font-weight: 700;
text-decoration: none;
}
.hero-cta:focus-visible { outline: 3px solid #fbbf24; outline-offset: 2px; }Text area
Multi-line text input. Visible label, programmatic association, aria-describedby for help text.
- Visible <label> linked by for/id — never a placeholder-only field (SC 1.3.5, 3.3.2).
- Help text uses aria-describedby so screen readers announce it after the label.
- Error state uses aria-invalid + aria-describedby pointing at the error message.
<div class="field">
<label for="bio">About you</label>
<p id="bio-help" class="field-help">A short paragraph — 1–3 sentences works best.</p>
<textarea id="bio" name="bio" rows="5" aria-describedby="bio-help"></textarea>
</div>.field {
display: flex;
flex-direction: column;
gap: 0.375rem;
margin-bottom: 1rem;
}
.field label {
font-weight: 700;
color: #1a1a1a;
}
.field-help {
margin: 0;
font-size: 0.875rem;
color: #3a3a3a;
}
.field textarea {
padding: 0.625rem;
font-family: inherit;
font-size: 1rem;
border: 2px solid #6b6b6b;
border-radius: 6px;
background: white;
color: #1a1a1a;
min-height: 6rem;
}
.field textarea:focus-visible {
outline: 3px solid #5b21b6;
outline-offset: 2px;
}
.field textarea[aria-invalid="true"] {
border-color: #b91c1c;
}Existing components
For accordion, tabs, and dropdown patterns — including live demos — see the dedicated pages:
