AccessibilityProvider
The AccessibilityProvider component provides comprehensive accessibility features and WCAG 2.1 AA compliance for React applications. It automatically detects system preferences, manages keyboard navigation, provides screen reader support, and includes development-time accessibility auditing.
Features
- ✅ System Preference Detection - Automatically detects high contrast, reduced motion preferences
- ✅ Keyboard Navigation - Enhanced focus indicators and keyboard user detection
- ✅ Screen Reader Support - ARIA live announcements and proper semantic markup
- ✅ Accessibility Auditing - Development-time issue detection and reporting
- ✅ WCAG 2.1 AA Compliance - Meets accessibility standards out of the box
- ✅ Zero Configuration - Works automatically with sensible defaults
Automatic Integration
AccessibilityProvider is automatically included in all QwickApp instances. No additional setup required!
// AccessibilityProvider is automatically applied
<QwickApp appName="My App">
<MyComponent /> {/* Automatically has accessibility features */}
</QwickApp>
Standalone Usage
For use outside of QwickApp:
import { AccessibilityProvider, useAccessibility } from '@qwickapps/react-framework';
function App() {
return (
<AccessibilityProvider enableAudit={true}>
<MyAccessibleComponent />
</AccessibilityProvider>
);
}
function MyAccessibleComponent() {
const { announce, highContrast, isKeyboardUser } = useAccessibility();
return (
<div>
{highContrast && <p>High contrast mode enabled</p>}
<button onClick={() => announce('Action completed')}>
Complete Action
</button>
</div>
);
}
useAccessibility Hook
Access accessibility features and state through the hook:
import { useAccessibility } from '@qwickapps/react-framework';
function MyComponent() {
const {
// System preferences
highContrast,
reducedMotion,
largeText,
// User interaction
isKeyboardUser,
focusVisible,
// Announcements
announce,
announcePolite,
announceAssertive,
// Controls
setHighContrast,
setReducedMotion,
setLargeText,
// Auditing
issues,
runAudit,
clearIssues
} = useAccessibility();
return (
<div>
<button
onClick={() => announce('Settings saved successfully')}
style={{
fontSize: largeText ? '1.2em' : '1em',
animation: reducedMotion ? 'none' : 'pulse 2s infinite'
}}
>
Save Settings
</button>
{issues.length > 0 && (
<div>Found {issues.length} accessibility issues</div>
)}
</div>
);
}
System Preferences
AccessibilityProvider automatically detects and responds to user system preferences:
High Contrast Mode
const { highContrast, setHighContrast } = useAccessibility();
// Automatically detected from system
// Can be manually controlled
<button
onClick={() => setHighContrast(!highContrast)}
className={highContrast ? 'high-contrast' : ''}
>
Toggle High Contrast
</button>
Reduced Motion
const { reducedMotion, setReducedMotion } = useAccessibility();
// Respects user's motion preferences
<div
style={{
animation: reducedMotion ? 'none' : 'fadeIn 0.3s ease-in'
}}
>
Content with respectful animations
</div>
Large Text
const { largeText, setLargeText } = useAccessibility();
// Enlarges text for better readability
<div style={{ fontSize: largeText ? '1.2em' : '1em' }}>
Resizable text content
</div>
Screen Reader Support
ARIA Live Announcements
Provide important updates to screen reader users:
const { announce, announcePolite, announceAssertive } = useAccessibility();
// Polite announcements (default)
announce('Form saved successfully');
announcePolite('Loading complete');
// Urgent announcements
announceAssertive('Error: Please fix required fields');
Announcement Levels:
- Polite - Announced when screen reader is idle
- Assertive - Interrupts current screen reader activity
Live Regions
AccessibilityProvider automatically creates ARIA live regions:
aria-live="polite"for non-urgent announcementsaria-live="assertive"for urgent announcements
Keyboard Navigation
Enhanced Focus Indicators
Automatically provides enhanced focus styles for keyboard users:
/* Automatically applied when using keyboard navigation */
.keyboard-user *:focus {
outline: 3px solid #005cee !important;
outline-offset: 2px !important;
}
.high-contrast *:focus {
outline: 3px solid #ffffff !important;
box-shadow: 0 0 0 1px #000000 !important;
}
Keyboard User Detection
const { isKeyboardUser } = useAccessibility();
// Automatically detects Tab key usage
// Switches back to mouse mode on mouse interaction
<div className={isKeyboardUser ? 'keyboard-user' : 'mouse-user'}>
Content with appropriate interaction styles
</div>
Accessibility Auditing
Development Mode Auditing
Automatically audits your application for common accessibility issues:
// Audit runs automatically in development mode
// Or manually enable/disable
<AccessibilityProvider enableAudit={true}>
<App />
</AccessibilityProvider>
Manual Auditing
const { runAudit, issues, clearIssues } = useAccessibility();
function AccessibilityPanel() {
return (
<div>
<button onClick={runAudit}>Run Accessibility Audit</button>
<button onClick={clearIssues}>Clear Issues</button>
{issues.length > 0 && (
<div>
<h3>Accessibility Issues ({issues.length})</h3>
{issues.map((issue, index) => (
<div key={index} className={`issue-${issue.level}`}>
<strong>{issue.type}:</strong> {issue.message}
</div>
))}
</div>
)}
</div>
);
}
Common Issues Detected
- Missing
altattributes on images - Unlabeled form inputs
- Buttons without accessible names
- Missing ARIA labels
- Poor color contrast (coming soon)
Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | - | Child components |
enableAudit | boolean | development mode | Enable accessibility auditing |
Accessibility State
The hook provides access to the complete accessibility state:
interface AccessibilityState {
highContrast: boolean; // High contrast mode enabled
reducedMotion: boolean; // Reduced motion preference
largeText: boolean; // Large text mode enabled
focusVisible: boolean; // Focus indicators visible
isKeyboardUser: boolean; // User is using keyboard navigation
issues: AccessibilityIssue[];// Current accessibility issues
lastAnnouncement: Announcement | null; // Last screen reader announcement
}
CSS Classes
AccessibilityProvider automatically applies CSS classes to the body:
.keyboard-user- When user is navigating with keyboard.high-contrast- When high contrast mode is enabled.reduced-motion- When reduced motion is preferred.large-text- When large text mode is enabled
Best Practices
- Use Semantic HTML - Start with proper HTML elements
- Provide Alt Text - Always include alt attributes for images
- Label Form Controls - Associate labels with form inputs
- Announce State Changes - Use announcements for dynamic content
- Respect User Preferences - Honor system accessibility settings
- Test with Keyboard - Ensure all functionality is keyboard accessible
- Run Regular Audits - Use the built-in auditing during development
Examples
Form with Accessibility Features
import { useAccessibility } from '@qwickapps/react-framework';
function AccessibleForm() {
const { announce, isKeyboardUser } = useAccessibility();
const [errors, setErrors] = useState([]);
const handleSubmit = async (data) => {
try {
await saveForm(data);
announce('Form saved successfully');
} catch (error) {
setErrors(error.fields);
announce('Please fix the form errors', 'assertive');
}
};
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">
Email Address
{errors.email && <span className="error" aria-live="polite">{errors.email}</span>}
</label>
<input
id="email"
type="email"
required
aria-describedby={errors.email ? "email-error" : undefined}
/>
<button
type="submit"
className={isKeyboardUser ? 'keyboard-focus' : ''}
>
Save Form
</button>
</form>
);
}
Dynamic Content Updates
function DataDashboard() {
const { announce } = useAccessibility();
const [data, setData] = useState(null);
const [loading, setLoading] = useState(false);
const refreshData = async () => {
setLoading(true);
announce('Loading data...');
try {
const newData = await fetchData();
setData(newData);
announce(`Data updated. Showing ${newData.length} items.`);
} catch (error) {
announce('Failed to load data. Please try again.', 'assertive');
} finally {
setLoading(false);
}
};
return (
<div>
<button onClick={refreshData} disabled={loading}>
Refresh Data
</button>
<div role="status" aria-live="polite">
{loading ? 'Loading...' : `${data?.length || 0} items`}
</div>
</div>
);
}
High Contrast Theme
function ThemeAwareComponent() {
const { highContrast, reducedMotion } = useAccessibility();
return (
<div
className={`
component
${highContrast ? 'high-contrast-theme' : ''}
${reducedMotion ? 'reduced-motion' : ''}
`}
style={{
backgroundColor: highContrast ? '#000000' : '#ffffff',
color: highContrast ? '#ffffff' : '#000000',
transition: reducedMotion ? 'none' : 'all 0.3s ease'
}}
>
Content that adapts to accessibility preferences
</div>
);
}