Accessibility¶
Accessibility is built into every decision in NS-OG 2.0. Nova Suite is designed to be usable by everyone, regardless of ability, device, or context. This page outlines our accessibility standards and implementation guidelines.
Core Principles¶
1. Perceivable¶
Information and user interface components must be presentable to users in ways they can perceive.
2. Operable¶
User interface components and navigation must be operable by everyone.
3. Understandable¶
Information and the operation of the user interface must be understandable.
4. Robust¶
Content must be robust enough to be interpreted by a wide variety of user agents, including assistive technologies.
Standards Compliance¶
Nova Suite adheres to:
- WCAG 2.1 Level AA (minimum standard)
- WCAG 2.2 Level AAA (where feasible)
- Section 508 compliance
- ARIA 1.2 specifications
Color & Contrast¶
Contrast Ratios¶
All text and interactive elements meet or exceed WCAG requirements:
| Element Type | Minimum Ratio | Our Standard |
|---|---|---|
| Normal text (< 18px) | 4.5:1 | 7:1 |
| Large text (≥ 18px) | 3:1 | 4.5:1 |
| UI components | 3:1 | 4.5:1 |
| Graphics | 3:1 | 4.5:1 |
Color Palette Accessibility¶
Orbit 2.0 colors are designed for maximum contrast:
/* Light mode - High contrast */
--text-primary: #1a1a1a; /* 16:1 on white */
--text-secondary: #4a5568; /* 7.2:1 on white */
--text-tertiary: #718096; /* 4.8:1 on white */
/* Dark mode - High contrast */
--text-primary-dark: #f7fafc; /* 18:1 on dark bg */
--text-secondary-dark: #cbd5e0; /* 10:1 on dark bg */
--text-tertiary-dark: #a0aec0; /* 6.5:1 on dark bg */
Testing Contrast¶
Use these tools to verify contrast:
- WebAIM Contrast Checker: webaim.org/resources/contrastchecker
- Browser DevTools: Built-in contrast audits
- Stark Plugin: Figma/Sketch accessibility plugin
Color Independence¶
Never rely on color alone to convey information:
Focus Management¶
Visible Focus Indicators¶
All interactive elements have clear focus states:
/* Default focus style */
*:focus-visible {
outline: 3px solid var(--focus-ring);
outline-offset: 2px;
border-radius: var(--radius-sm);
}
/* Custom focus for buttons */
.button:focus-visible {
outline: 3px solid var(--primary);
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.2);
}
Focus ring colors: - Light mode: #6366f1 (Indigo) - Dark mode: #818cf8 (Lighter indigo) - Contrast: Always 3:1 minimum against background
Focus Order¶
Ensure logical tab order matches visual layout:
<!-- Correct tab order -->
<form>
<input type="text" tabindex="1" /> <!-- First -->
<input type="email" tabindex="2" /> <!-- Second -->
<button tabindex="3">Submit</button> <!-- Third -->
</form>
Best practices: - Don't use positive tabindex values unnecessarily - Use tabindex="0" to make custom elements focusable - Use tabindex="-1" to remove elements from tab order - Test keyboard navigation thoroughly
Skip Links¶
Provide skip navigation for keyboard users:
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<main id="main-content">
<!-- Page content -->
</main>
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: var(--primary);
color: white;
padding: 8px;
z-index: 1000;
}
.skip-link:focus {
top: 0;
}
Interactive Elements¶
Touch Targets¶
Minimum size for all interactive elements:
/* Minimum 44×44px per WCAG 2.1 */
.button,
.link-interactive,
.checkbox,
.radio,
.toggle {
min-width: 44px;
min-height: 44px;
}
/* If visual size is smaller, use padding */
.icon-button {
width: 24px; /* Visual size */
height: 24px;
padding: 10px; /* Total: 44px */
}
Target spacing: - Minimum 8px spacing between interactive elements - 16px recommended for complex interfaces
Button States¶
Provide clear visual feedback for all states:
.button {
/* Default state */
background: var(--primary);
color: white;
/* Hover state */
&:hover {
background: var(--primary-hover);
transform: translateY(-1px);
}
/* Focus state */
&:focus-visible {
outline: 3px solid var(--focus-ring);
outline-offset: 2px;
}
/* Active state */
&:active {
transform: translateY(0);
}
/* Disabled state */
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
Semantic HTML¶
Use Proper Elements¶
<!-- ✅ Good: Semantic HTML -->
<nav aria-label="Main navigation">
<ul>
<li><a href="/home">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<main>
<article>
<h1>Page Title</h1>
<section>
<h2>Section Heading</h2>
<p>Content...</p>
</section>
</article>
</main>
<!-- ❌ Bad: Div soup -->
<div class="nav">
<div class="link">Home</div>
<div class="link">About</div>
</div>
<div class="main">
<div class="title">Page Title</div>
<div class="text">Content...</div>
</div>
Heading Hierarchy¶
Maintain logical heading structure:
<h1>Page Title</h1> <!-- Only one H1 per page -->
<h2>Major Section</h2>
<h3>Subsection</h3>
<h3>Another Subsection</h3>
<h2>Another Major Section</h2>
<h3>Subsection</h3>
Don't skip levels:
<!-- ❌ Bad: Skips H2 -->
<h1>Title</h1>
<h3>Subsection</h3>
<!-- ✅ Good: Proper hierarchy -->
<h1>Title</h1>
<h2>Section</h2>
<h3>Subsection</h3>
ARIA Implementation¶
ARIA Roles¶
Use ARIA roles to enhance semantic meaning:
<!-- Navigation -->
<nav role="navigation" aria-label="Main navigation">
<ul role="list">
<li role="listitem"><a href="/">Home</a></li>
</ul>
</nav>
<!-- Search -->
<div role="search">
<label for="search-input">Search</label>
<input id="search-input" type="search" aria-label="Search documentation" />
</div>
<!-- Alert -->
<div role="alert" aria-live="polite">
Your changes have been saved.
</div>
ARIA Labels¶
Provide descriptive labels for all interactive elements:
<!-- Icon buttons need labels -->
<button aria-label="Close dialog">
<svg class="icon-close">...</svg>
</button>
<!-- Expandable sections -->
<button
aria-expanded="false"
aria-controls="section-content"
aria-label="Expand section">
Show more
</button>
<div id="section-content" hidden>
<!-- Content -->
</div>
ARIA Live Regions¶
Announce dynamic content changes:
<!-- Polite: Announces when user is idle -->
<div aria-live="polite" aria-atomic="true">
<p>3 new messages</p>
</div>
<!-- Assertive: Announces immediately -->
<div aria-live="assertive" role="alert">
<p>Error: Form submission failed</p>
</div>
Screen Reader Support¶
Descriptive Text¶
Provide context for screen reader users:
<!-- Link text should be descriptive -->
<!-- ✅ Good -->
<a href="/docs">Read the documentation</a>
<!-- ❌ Bad -->
<a href="/docs">Click here</a>
<!-- Images need alt text -->
<img src="chart.png" alt="Sales increased 23% in Q4 2024" />
<!-- Decorative images -->
<img src="decoration.png" alt="" role="presentation" />
Visually Hidden Content¶
Provide additional context for screen readers:
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
Forms & Inputs¶
Labels & Instructions¶
All inputs must have associated labels:
<!-- ✅ Explicit label -->
<label for="email">Email Address</label>
<input id="email" type="email" required />
<!-- ✅ Implicit label -->
<label>
Email Address
<input type="email" required />
</label>
<!-- ✅ With help text -->
<label for="password">Password</label>
<input
id="password"
type="password"
aria-describedby="password-help"
required
/>
<p id="password-help">Must be at least 8 characters</p>
Error Handling¶
Provide clear, accessible error messages:
<div class="form-group">
<label for="username">Username</label>
<input
id="username"
type="text"
aria-invalid="true"
aria-describedby="username-error"
required
/>
<p id="username-error" role="alert" class="error-message">
Username is required and must be at least 3 characters
</p>
</div>
/* Visual error indicator */
input[aria-invalid="true"] {
border-color: var(--error);
box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.1);
}
.error-message {
color: var(--error);
font-size: 0.875rem;
margin-top: var(--space-xs);
}
Mobile & Touch Accessibility¶
Touch Gestures¶
Provide alternatives to complex gestures:
- Swipe: Provide button alternatives
- Pinch-to-zoom: Allow browser zoom
- Long press: Provide tap alternatives
Orientation Support¶
Support both portrait and landscape:
/* Don't lock orientation */
@media (orientation: landscape) {
/* Adjust layout, don't hide content */
}
Reduced Motion¶
Respect user preferences for reduced motion:
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
Testing Checklist¶
Keyboard Navigation¶
- All interactive elements are keyboard accessible
- Tab order is logical and matches visual order
- Focus indicators are clearly visible
- No keyboard traps
- Skip links work correctly
Screen Readers¶
- Test with NVDA (Windows) or JAWS
- Test with VoiceOver (macOS/iOS)
- Test with TalkBack (Android)
- All images have appropriate alt text
- Form labels are properly associated
Color & Contrast¶
- All text meets contrast requirements
- Interactive elements meet contrast requirements
- Color is not the only means of conveying information
- Test in grayscale
Responsive & Zoom¶
- Content is readable at 200% zoom
- No horizontal scrolling at standard widths
- Touch targets are at least 44×44px
- Works on mobile devices
Tools¶
Use these tools for testing:
- axe DevTools: Browser extension for accessibility audits
- WAVE: Web accessibility evaluation tool
- Lighthouse: Built into Chrome DevTools
- pa11y: Automated accessibility testing
- Screen reader: Test with real screen readers
Resources¶
Guidelines & Standards¶
Testing Tools¶
Learning¶
Accessibility is not optional—it's essential. By following these guidelines, we ensure Nova Suite is usable by everyone, creating a more inclusive digital experience.