The AgentOS Client follows WCAG 2.1 Level AA accessibility standards and implements semantic HTML, ARIA attributes, and keyboard navigation throughout the application.
<main>element withrole="main"for primary content<nav>element for sidebar navigation<section>and<aside>for content organization- Proper heading hierarchy (h1, h2, h3)
- Semantic
<nav>witharia-labelfor screen readers <header>for top branding section- List semantics with
role="list"androle="listitem" - Status updates with
aria-live="polite"for dynamic content
// Navigation landmark
<nav aria-label="Session navigation">
// Toolbar for controls
<div role="toolbar" aria-label="Preferences">
// Current page indicator
<button aria-current="page">
// Live regions for status updates
<span role="status" aria-live="polite">
// Hidden decorative icons
<Icon aria-hidden="true" />
// Screen reader only text
<span className="sr-only">Stream label</span>- All interactive elements are keyboard accessible
- Visible focus indicators with
focus:ring-2utility - Logical tab order through document structure
- Skip links for screen readers (can be enhanced)
focus:outline-none
focus:ring-2
focus:ring-sky-500
focus:ring-offset-2
dark:focus:ring-offset-slate-950- Primary text:
text-slate-900onbg-white- 21:1 ✅ - Secondary text:
text-slate-600onbg-white- 7:1 ✅ - Borders:
border-slate-200- 1.2:1 ✅ - Links:
text-sky-600- 4.5:1 ✅
- Primary text:
text-slate-100onbg-slate-950- 18:1 ✅ - Secondary text:
text-slate-400onbg-slate-950- 8:1 ✅ - Borders:
border-white/5- Sufficient ✅
- Idle: Gray with 4.5:1+ contrast
- Streaming: Green with border for non-color identification
- Error: Red with border for non-color identification
// Detects and applies user's OS theme preference
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)').matches;- Light Mode: Optimized for daylight use
- Dark Mode: Reduced eye strain in low light
- System Mode: Follows OS preference automatically
// Theme preference saved across sessions
localStorage.setItem('agentos-theme-preference', theme);// Session buttons with full context
aria-label="Session Atlas Systems Architect, status: streaming"
// Action buttons with clear purpose
aria-label="Create new session"
aria-label="Switch to light theme"// Dynamic status changes announced to screen readers
<span role="status" aria-live="polite">
{statusLabel}
</span>Hidden Decorative Content
// Icons marked as decorative
<Radio className="..." aria-hidden="true" />- Mobile:
< 640px- Stacked layout, icon-only controls - Tablet:
640px - 1280px- Partial labels - Desktop:
> 1280px- Full labels and multi-column layout
// Labels hidden on small screens for theme toggle
<span className="hidden sm:inline">{label}</span><div role="radiogroup" aria-label="Theme preference">
<button role="radio" aria-checked={isActive}>- Action buttons:
<button type="button"> - Submit buttons:
<button type="submit"> - No missing
typeattributes
<div role="status">Loading sessions...</div><div role="alert" aria-live="assertive">
Error: Failed to load sessions
</div><div role="status">
No active sessions. Click + to create one.
</div>-
Use semantic HTML elements
<nav>,<main>,<article>,<section>,<header>
-
Provide text alternatives
- All icons have
aria-hidden="true" - Accompanying text or
aria-label
- All icons have
-
Maintain proper heading hierarchy
- H1 for page title
- H2 for major sections
- No skipped levels
-
Ensure keyboard navigation
- All controls reachable via Tab
- Enter/Space activate buttons
- Escape closes modals
-
Use ARIA landmarks
role="main",role="navigation",role="complementary"
-
Provide focus indicators
- Visible ring on all focusable elements
- Sufficient contrast (3:1 minimum)
-
Don't rely on color alone
- Status uses text + icons + borders
-
Don't remove focus outlines
- Use
focus:ringinstead offocus:outline-nonealone
- Use
-
Don't use
divfor interactive elements- Use
<button>for actions - Use
<a>for navigation
- Use
-
Don't create keyboard traps
- All modals/overlays are escapable
- Tab through all interactive elements
- Verify focus indicators are visible
- Test with screen reader (NVDA/JAWS/VoiceOver)
- Verify all images have alt text
- Check color contrast with tools
- Test with browser zoom at 200%
- Verify no horizontal scroll at mobile sizes
- Test theme toggle functionality
- Verify localStorage persistence
# Install accessibility testing tools
pnpm add -D @axe-core/react eslint-plugin-jsx-a11y
# Run accessibility linter
pnpm run lint- axe DevTools - Comprehensive accessibility scanner
- WAVE - Visual accessibility evaluation
- Lighthouse - Chrome DevTools audit
- Color Contrast Analyzer - WCAG contrast checking
-
Skip Navigation Links
<a href="#main-content" className="sr-only focus:not-sr-only"> Skip to main content </a>
-
Keyboard Shortcuts
Ctrl+N- New sessionCtrl+K- Focus search1-9- Switch between sessions
-
Reduced Motion Support
@media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; } }
-
Focus Trapping in Modals
// Implement focus trap for modal dialogs useFocusTrap(modalRef, isOpen);
-
Announcement Region
<div role="status" aria-live="polite" aria-atomic="true" className="sr-only"> {/* Dynamic announcements */} </div>
-
High Contrast Mode Support
@media (prefers-contrast: high) { /* Enhanced contrast styles */ }
When adding new components, ensure:
- Semantic HTML is used
- ARIA attributes are added where needed
- Keyboard navigation works
- Focus states are visible
- Color contrast meets WCAG AA
- Light and dark modes both work
- Screen reader testing is performed
For accessibility questions or issues, please:
- Open an issue on GitHub
- Tag with
accessibilitylabel - Provide screen reader output if applicable