Trauma-Informed Design Principles
Users seeking immigration legal aid frequently operate under extreme psychological duress. Public service interfaces must practice trauma-informed design, rooted in SAMHSA principles:
| Principle | Design Implementation |
|---|---|
| Safety | Predictable, calming interfaces |
| Trustworthiness | Clear sourcing, transparent attribution |
| Peer Support | Community connection, shared experiences |
| Collaboration | User control over information depth |
| Empowerment | Clear action paths, agency |
| Cultural Sensitivity | Multilingual, inclusive imagery |
Cognitive Accessibility
Reducing Cognitive Load
Users under stress have severely degraded working memory. Design must minimize cognitive demands:
| Strategy | Implementation |
|---|---|
| Simplify language | Grade 6-8 reading level |
| Chunk information | 3-item groupings |
| Progressive disclosure | Simple first, details on demand |
| Predictable patterns | Consistent navigation |
| Reduce choices | Limit options per screen |
Reading Level Guidelines
❌ AVOID:
"Pursuant to the Fourth Amendment protections afforded
under the Constitution, you maintain the right to decline
warrantless intrusion into your domicile."
✅ USE:
"You do not have to let ICE into your home without a
warrant signed by a judge."
Error Recovery
Unpredictable interfaces create anxiety feedback loops. Provide clear error recovery:
<div class="error-message" role="alert">
<h3>We couldn't submit your form</h3>
<p>The phone number format isn't recognized.</p>
<p><strong>Try this:</strong> Enter 10 digits like 555-123-4567</p>
<button>Try Again</button>
</div>
Loading States
Skeleton loaders reduce anxiety during slow connections:
.skeleton {
background: linear-gradient(
90deg,
var(--color-skeleton) 25%,
var(--color-skeleton-highlight) 50%,
var(--color-skeleton) 75%
);
background-size: 200% 100%;
animation: skeleton-pulse 1.5s ease-in-out infinite;
}
@keyframes skeleton-pulse {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
Screen Reader Optimization
Heading Hierarchy
Legal documents require rigorous semantic structure:
<h1>Your Rights During a Home Raid</h1>
<h2>Before Opening the Door</h2>
<h3>Identifying the Officers</h3>
<h3>Asking for a Warrant</h3>
<h2>If They Enter Without Consent</h2>
<h3>What to Say</h3>
<h3>What to Document</h3>
Never skip heading levels. Skipping confuses screen readers and destroys document outline.
Landmark Regions
<body>
<header role="banner">
<nav role="navigation" aria-label="Main">...</nav>
</header>
<main role="main" id="main-content">
<article>
<h1>Know Your Rights</h1>
...
</article>
<aside role="complementary" aria-label="Related resources">
...
</aside>
</main>
<footer role="contentinfo">...</footer>
</body>
Skip Links
Essential for lengthy legal pages:
<a href="#main-content" class="skip-link">
Skip to main content
</a>
.skip-link {
position: absolute;
left: -10000px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
}
.skip-link:focus {
position: static;
width: auto;
height: auto;
padding: 1rem;
background: var(--color-primary);
color: white;
}
ARIA Implementation
Accordion Components
<div class="accordion">
<h3>
<button aria-expanded="false"
aria-controls="panel-1"
id="accordion-1">
What if ICE comes to my door?
</button>
</h3>
<div id="panel-1"
role="region"
aria-labelledby="accordion-1"
hidden>
<p>You have the right to not open the door...</p>
</div>
</div>
// Toggle accordion
button.addEventListener('click', () => {
const expanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', !expanded);
panel.hidden = expanded;
});
Live Regions for Updates
Legal disclaimers and dynamic content:
<!-- Polite announcement for disclaimers -->
<div aria-live="polite" aria-atomic="true">
<p class="disclaimer">
This information is not legal advice.
</p>
</div>
<!-- Assertive for critical alerts -->
<div role="alert" aria-live="assertive">
<p>Emergency: ICE raid reported in your area</p>
</div>
Modal Focus Trapping
function openModal(modal) {
const focusableElements = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstFocusable = focusableElements[0];
const lastFocusable = focusableElements[focusableElements.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstFocusable) {
lastFocusable.focus();
e.preventDefault();
} else if (!e.shiftKey && document.activeElement === lastFocusable) {
firstFocusable.focus();
e.preventDefault();
}
}
if (e.key === 'Escape') {
closeModal(modal);
}
});
firstFocusable.focus();
}
Keyboard Navigation
Focus Indicators
Must be visible across all color schemes:
:focus {
outline: 3px solid var(--color-focus);
outline-offset: 2px;
}
/* Enhanced for high contrast mode */
@media (prefers-contrast: high) {
:focus {
outline-width: 4px;
outline-color: currentColor;
}
}
Keyboard Interactions
| Element | Expected Keys |
|---|---|
| Button | Enter, Space |
| Link | Enter |
| Accordion | Enter, Space, Arrow keys |
| Modal | Escape to close |
| Tab panel | Arrow keys to switch |
Interactive Map Keyboard Support
// Map marker keyboard navigation
markers.forEach((marker, index) => {
marker.getElement().setAttribute('tabindex', '0');
marker.getElement().setAttribute('role', 'button');
marker.getElement().addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
marker.openPopup();
e.preventDefault();
}
if (e.key === 'ArrowRight') {
markers[index + 1]?.getElement().focus();
}
if (e.key === 'ArrowLeft') {
markers[index - 1]?.getElement().focus();
}
});
});
Color Accessibility
Contrast Requirements
| Element | Minimum Ratio |
|---|---|
| Body text | 4.5:1 |
| Large text (18px+) | 3:1 |
| UI components | 3:1 |
| Focus indicators | 3:1 |
Color Not Sole Indicator
/* ❌ Color only */
.error { color: red; }
/* ✅ Color + icon + text */
.error {
color: var(--color-error);
border-left: 4px solid var(--color-error);
}
.error::before {
content: "⚠ ";
}
Colorblind-Safe Palette
| Status | Color | Pattern Alternative |
|---|---|---|
| Error | #D32F2F | Triangle icon, striped border |
| Warning | #F57C00 | Diamond icon, dashed border |
| Success | #388E3C | Circle icon, solid border |
| Info | #1976D2 | Square icon, dotted border |
Dark Mode
:root {
--color-text: #1a1a1a;
--color-bg: #ffffff;
}
@media (prefers-color-scheme: dark) {
:root {
--color-text: #e0e0e0;
--color-bg: #1a1a2e;
}
}
Typography for Readability
Dyslexia-Friendly Fonts
Sans-serif fonts with distinct letterforms:
body {
font-family: 'Atkinson Hyperlegible', 'Inter', sans-serif;
letter-spacing: 0.02em;
word-spacing: 0.05em;
}
Line Length and Spacing
.content {
max-width: 70ch; /* 60-75 characters */
line-height: 1.6;
}
p + p {
margin-top: 1.5em;
}
Resizable Text
Support browser zoom and text-only scaling:
/* Use relative units */
body {
font-size: 100%; /* Respects user preference */
}
h1 { font-size: 2rem; }
p { font-size: 1rem; }
/* Never use px for font sizes */
Motor Accessibility
Touch Target Sizes
| Standard | Minimum | Advocacy Recommendation |
|---|---|---|
| Apple | 44px | 56px for crisis actions |
| 48dp | 56dp under stress | |
| WCAG | 44×44px | 56×56px with spacing |
Spacing Between Targets
.button-group {
display: flex;
gap: 12px; /* Minimum 8px, prefer 12px */
}
.button {
padding: 1rem 1.5rem;
min-height: 56px;
}
Alternatives to Gestures
<!-- Always provide button alternatives to swipe -->
<div class="carousel">
<button class="carousel-prev" aria-label="Previous">←</button>
<div class="carousel-content">...</div>
<button class="carousel-next" aria-label="Next">→</button>
</div>
Testing Checklist
Automated Testing
- [ ] axe DevTools audit passed
- [ ] WAVE extension check
- [ ] Lighthouse accessibility > 90
- [ ] Pa11y CI integration
Manual Testing
- [ ] Keyboard-only navigation complete
- [ ] Screen reader tested (NVDA, VoiceOver)
- [ ] 200% zoom functional
- [ ] High contrast mode visible
- [ ] Motion reduced respected
Screen Reader Testing
| Reader | Platform | Testing Command |
|---|---|---|
| NVDA | Windows | Free download |
| VoiceOver | macOS | Cmd + F5 |
| TalkBack | Android | Built-in |
| VoiceOver | iOS | Settings → Accessibility |
Related Resources
- Component Library - Accessible components
- Multilingual UX - RTL accessibility
- Mobile-First - Touch accessibility
- Map Accessibility - Interactive maps