|
| 1 | +# Accessibility Guidelines |
| 2 | + |
| 3 | +This document outlines accessibility best practices for the AFT application to ensure all features are usable by everyone, including users with disabilities. |
| 4 | + |
| 5 | +## General Principles |
| 6 | + |
| 7 | +1. **Semantic HTML**: Use appropriate HTML elements for their intended purpose (e.g., `<button>` for buttons, `<nav>` for navigation) |
| 8 | +2. **Keyboard Navigation**: All interactive elements must be keyboard accessible |
| 9 | +3. **Screen Reader Support**: Provide appropriate ARIA attributes and alternative text |
| 10 | +4. **Color Contrast**: Ensure sufficient contrast ratios for text and interactive elements |
| 11 | +5. **Focus Management**: Visible focus indicators and logical tab order |
| 12 | + |
| 13 | +## Modal Dialogs |
| 14 | + |
| 15 | +All modal dialogs MUST include the following ARIA attributes: |
| 16 | + |
| 17 | +```html |
| 18 | +<div id="myModal" class="modal" |
| 19 | + role="dialog" |
| 20 | + aria-modal="true" |
| 21 | + aria-labelledby="modal-title" |
| 22 | + aria-describedby="modal-description"> |
| 23 | + <div class="modal-content"> |
| 24 | + <div class="modal-header"> |
| 25 | + <h2 id="modal-title">Modal Title</h2> |
| 26 | + </div> |
| 27 | + <div class="modal-body"> |
| 28 | + <p id="modal-description">Modal description text</p> |
| 29 | + </div> |
| 30 | + <div class="modal-actions"> |
| 31 | + <button class="btn btn-secondary">Cancel</button> |
| 32 | + <button class="btn btn-primary">Confirm</button> |
| 33 | + </div> |
| 34 | + </div> |
| 35 | +</div> |
| 36 | +``` |
| 37 | + |
| 38 | +### Required Attributes: |
| 39 | +- `role="dialog"` - Identifies the element as a dialog |
| 40 | +- `aria-modal="true"` - Indicates this is a modal dialog that blocks interaction with the rest of the page |
| 41 | +- `aria-labelledby` - References the ID of the element containing the modal's title |
| 42 | +- `aria-describedby` - References the ID of the element containing the modal's description |
| 43 | + |
| 44 | +### JavaScript Considerations: |
| 45 | +- Trap focus within the modal when open |
| 46 | +- Return focus to the triggering element when closed |
| 47 | +- Allow ESC key to close the modal |
| 48 | +- Disable background scrolling when modal is open |
| 49 | + |
| 50 | +## Forms |
| 51 | + |
| 52 | +### Labels |
| 53 | +Every form input MUST have an associated label: |
| 54 | + |
| 55 | +```html |
| 56 | +<label for="inputId">Field Name</label> |
| 57 | +<input type="text" id="inputId" name="fieldName"> |
| 58 | +``` |
| 59 | + |
| 60 | +### Required Fields |
| 61 | +Indicate required fields both visually and programmatically: |
| 62 | + |
| 63 | +```html |
| 64 | +<label for="email">Email <span aria-label="required">*</span></label> |
| 65 | +<input type="email" id="email" required aria-required="true"> |
| 66 | +``` |
| 67 | + |
| 68 | +### Error Messages |
| 69 | +Associate error messages with their inputs: |
| 70 | + |
| 71 | +```html |
| 72 | +<label for="username">Username</label> |
| 73 | +<input type="text" id="username" aria-describedby="username-error" aria-invalid="true"> |
| 74 | +<div id="username-error" role="alert">Username is required</div> |
| 75 | +``` |
| 76 | + |
| 77 | +## Buttons and Links |
| 78 | + |
| 79 | +### Icons |
| 80 | +Provide text alternatives for icon-only buttons: |
| 81 | + |
| 82 | +```html |
| 83 | +<!-- Option 1: aria-label --> |
| 84 | +<button aria-label="Delete item">🗑️</button> |
| 85 | + |
| 86 | +<!-- Option 2: Visually hidden text --> |
| 87 | +<button> |
| 88 | + <span class="sr-only">Delete item</span> |
| 89 | + <span aria-hidden="true">🗑️</span> |
| 90 | +</button> |
| 91 | +``` |
| 92 | + |
| 93 | +### Toggle Buttons |
| 94 | +Indicate state for toggle buttons: |
| 95 | + |
| 96 | +```html |
| 97 | +<button type="button" |
| 98 | + aria-pressed="false" |
| 99 | + id="backupToggle"> |
| 100 | + Enable Backups |
| 101 | +</button> |
| 102 | +``` |
| 103 | + |
| 104 | +## Status Messages |
| 105 | + |
| 106 | +Use ARIA live regions for dynamic status updates: |
| 107 | + |
| 108 | +```html |
| 109 | +<!-- Polite: Announces when user is idle --> |
| 110 | +<div role="status" aria-live="polite" aria-atomic="true" id="status-message"> |
| 111 | + Settings saved successfully |
| 112 | +</div> |
| 113 | + |
| 114 | +<!-- Assertive: Announces immediately (errors) --> |
| 115 | +<div role="alert" aria-live="assertive" aria-atomic="true" id="error-message"> |
| 116 | + Failed to save settings |
| 117 | +</div> |
| 118 | +``` |
| 119 | + |
| 120 | +## Loading States |
| 121 | + |
| 122 | +Indicate loading states to screen readers: |
| 123 | + |
| 124 | +```html |
| 125 | +<button aria-busy="true" disabled> |
| 126 | + <span role="status">Loading...</span> |
| 127 | +</button> |
| 128 | +``` |
| 129 | + |
| 130 | +## Images |
| 131 | + |
| 132 | +All images must have appropriate alt text: |
| 133 | + |
| 134 | +```html |
| 135 | +<!-- Decorative images --> |
| 136 | +<img src="decoration.png" alt="" role="presentation"> |
| 137 | + |
| 138 | +<!-- Informative images --> |
| 139 | +<img src="chart.png" alt="Bar chart showing 25% increase in sales"> |
| 140 | +``` |
| 141 | + |
| 142 | +## Tables |
| 143 | + |
| 144 | +Use proper table structure with headers: |
| 145 | + |
| 146 | +```html |
| 147 | +<table> |
| 148 | + <thead> |
| 149 | + <tr> |
| 150 | + <th scope="col">Name</th> |
| 151 | + <th scope="col">Date</th> |
| 152 | + <th scope="col">Size</th> |
| 153 | + </tr> |
| 154 | + </thead> |
| 155 | + <tbody> |
| 156 | + <tr> |
| 157 | + <td>backup.sql</td> |
| 158 | + <td>2025-11-30</td> |
| 159 | + <td>2.5 MB</td> |
| 160 | + </tr> |
| 161 | + </tbody> |
| 162 | +</table> |
| 163 | +``` |
| 164 | + |
| 165 | +## Navigation |
| 166 | + |
| 167 | +### Skip Links |
| 168 | +Provide skip navigation links: |
| 169 | + |
| 170 | +```html |
| 171 | +<a href="#main-content" class="skip-link">Skip to main content</a> |
| 172 | +<main id="main-content"> |
| 173 | + <!-- Page content --> |
| 174 | +</main> |
| 175 | +``` |
| 176 | + |
| 177 | +### Landmarks |
| 178 | +Use semantic landmarks or ARIA roles: |
| 179 | + |
| 180 | +```html |
| 181 | +<header role="banner"> |
| 182 | +<nav role="navigation" aria-label="Main navigation"> |
| 183 | +<main role="main"> |
| 184 | +<aside role="complementary"> |
| 185 | +<footer role="contentinfo"> |
| 186 | +``` |
| 187 | + |
| 188 | +## Testing |
| 189 | + |
| 190 | +### Manual Testing Checklist |
| 191 | +- [ ] Keyboard navigation (Tab, Shift+Tab, Enter, Escape, Arrow keys) |
| 192 | +- [ ] Screen reader testing (NVDA, JAWS, or VoiceOver) |
| 193 | +- [ ] Focus indicators visible |
| 194 | +- [ ] Color contrast ratios pass WCAG AA (4.5:1 for normal text) |
| 195 | +- [ ] Zoom to 200% without loss of functionality |
| 196 | +- [ ] No reliance on color alone for information |
| 197 | + |
| 198 | +### Tools |
| 199 | +- **axe DevTools**: Browser extension for automated accessibility testing |
| 200 | +- **WAVE**: Web accessibility evaluation tool |
| 201 | +- **Lighthouse**: Built into Chrome DevTools |
| 202 | +- **Screen Readers**: |
| 203 | + - Windows: NVDA (free) or JAWS |
| 204 | + - macOS: VoiceOver (built-in) |
| 205 | + - Linux: Orca |
| 206 | + |
| 207 | +## Resources |
| 208 | + |
| 209 | +- [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/) |
| 210 | +- [MDN Accessibility](https://developer.mozilla.org/en-US/docs/Web/Accessibility) |
| 211 | +- [ARIA Authoring Practices Guide](https://www.w3.org/WAI/ARIA/apg/) |
| 212 | +- [WebAIM](https://webaim.org/) |
| 213 | + |
| 214 | +## Implementation Checklist for New Features |
| 215 | + |
| 216 | +When adding new features, ensure: |
| 217 | + |
| 218 | +- [ ] All interactive elements are keyboard accessible |
| 219 | +- [ ] All images have appropriate alt text |
| 220 | +- [ ] All forms have proper labels and error handling |
| 221 | +- [ ] All modals have proper ARIA attributes |
| 222 | +- [ ] All status messages use live regions |
| 223 | +- [ ] Color contrast meets WCAG AA standards |
| 224 | +- [ ] Focus management is handled correctly |
| 225 | +- [ ] Screen reader testing completed |
| 226 | +- [ ] Documentation updated if needed |
0 commit comments