0
# Accessibility Features
1
2
## Overview
3
4
@primer/octicons-react provides comprehensive accessibility support through ARIA attributes, semantic markup, and keyboard navigation features. All icons are designed to work seamlessly with screen readers and assistive technologies.
5
6
## ARIA Attributes
7
8
### Automatic ARIA Behavior
9
10
Icons automatically set `aria-hidden` and `role` attributes based on labeling:
11
- When `aria-label` or `aria-labelledby` is provided: `role="img"` and `aria-hidden` is unset
12
- When no labeling is provided: `aria-hidden="true"` (decorative)
13
14
### Labeling Options
15
16
```typescript { .api }
17
interface AriaProps {
18
/** Accessible label for screen readers */
19
'aria-label'?: string
20
/** References element that labels this icon */
21
'aria-labelledby'?: string
22
/** Title text for tooltips and additional context */
23
title?: string | React.ReactElement<any>
24
}
25
```
26
27
### aria-label Usage
28
29
Use `aria-label` to provide descriptive text for icons that convey meaning:
30
31
```jsx
32
import { PlusIcon, AlertIcon, CheckIcon } from '@primer/octicons-react'
33
34
function AccessibleIcons() {
35
return (
36
<div>
37
<button>
38
<PlusIcon aria-label="Add new item" />
39
New
40
</button>
41
42
<div>
43
<AlertIcon aria-label="Warning: Please review your input" />
44
Form validation error
45
</div>
46
47
<span>
48
<CheckIcon aria-label="Task completed successfully" />
49
Done
50
</span>
51
</div>
52
)
53
}
54
```
55
56
### aria-labelledby Usage
57
58
Use `aria-labelledby` when an existing element provides the label:
59
60
```jsx
61
import { PlusIcon, GearIcon } from '@primer/octicons-react'
62
63
function LabelledByExample() {
64
return (
65
<div>
66
<h2 id="settings-title">Account Settings</h2>
67
<GearIcon aria-labelledby="settings-title" />
68
69
<button>
70
<PlusIcon aria-labelledby="add-button-label" title="Create new project" />
71
<span id="add-button-label">Add Project</span>
72
</button>
73
</div>
74
)
75
}
76
```
77
78
## Keyboard Navigation
79
80
### Tab Index Control
81
82
```typescript { .api }
83
interface KeyboardProps {
84
/** Tab order for keyboard navigation */
85
tabIndex?: number
86
}
87
```
88
89
**Tab Index Values:**
90
- `0`: Include in natural tab order
91
- `-1`: Focusable via JavaScript but not in tab order
92
- `undefined` (default): Not focusable
93
94
```jsx
95
import { SearchIcon, CloseIcon } from '@primer/octicons-react'
96
97
function InteractiveIcons() {
98
return (
99
<div>
100
{/* Focusable search icon */}
101
<SearchIcon
102
aria-label="Open search"
103
tabIndex={0}
104
onClick={handleSearch}
105
onKeyDown={handleKeyDown}
106
/>
107
108
{/* Close button that's keyboard accessible */}
109
<CloseIcon
110
aria-label="Close dialog"
111
tabIndex={0}
112
role="button"
113
onClick={handleClose}
114
onKeyDown={(e) => {
115
if (e.key === 'Enter' || e.key === ' ') {
116
handleClose()
117
}
118
}}
119
/>
120
121
{/* Decorative icon - not focusable */}
122
<StarIcon aria-hidden="true" />
123
</div>
124
)
125
}
126
```
127
128
## SVG Accessibility Features
129
130
### Automatic ARIA Handling
131
132
Icons automatically manage ARIA attributes based on provided props:
133
134
```typescript { .api }
135
interface AutoAriaProps {
136
/** Automatically set based on other props */
137
'aria-hidden'?: 'true' | undefined
138
/** Automatically set when aria-label or aria-labelledby provided */
139
role?: 'img' | undefined
140
/** Controlled by tabIndex prop */
141
focusable?: 'true' | 'false'
142
}
143
```
144
145
**Automatic Behavior:**
146
- `aria-hidden="true"` when no accessibility props provided
147
- `role="img"` when `aria-label` or `aria-labelledby` provided
148
- `focusable="false"` when `tabIndex` is undefined or negative
149
- `focusable="true"` when `tabIndex` is 0 or positive
150
151
### Title Elements
152
153
The `title` prop creates an SVG `<title>` element for additional context:
154
155
```jsx
156
import { InfoIcon, WarningIcon } from '@primer/octicons-react'
157
158
function TitledIcons() {
159
return (
160
<div>
161
<InfoIcon
162
title="Additional information available"
163
aria-label="Information"
164
/>
165
166
<WarningIcon
167
title="This action cannot be undone"
168
aria-label="Warning"
169
/>
170
</div>
171
)
172
}
173
```
174
175
## Decorative vs Semantic Icons
176
177
### Decorative Icons
178
179
Icons that don't convey unique information should be hidden from screen readers:
180
181
```jsx
182
import { StarIcon, HeartIcon } from '@primer/octicons-react'
183
184
function DecorativeIcons() {
185
return (
186
<div>
187
{/* Text already conveys the meaning */}
188
<span>
189
<StarIcon aria-hidden="true" />
190
Starred Repository
191
</span>
192
193
{/* Icon is purely visual decoration */}
194
<h1>
195
<HeartIcon aria-hidden="true" />
196
Favorite Projects
197
</h1>
198
</div>
199
)
200
}
201
```
202
203
### Semantic Icons
204
205
Icons that convey important information need accessibility attributes:
206
207
```jsx
208
import { AlertIcon, CheckCircleIcon, XCircleIcon } from '@primer/octicons-react'
209
210
function SemanticIcons() {
211
return (
212
<div>
213
{/* Status indicators */}
214
<div>
215
<CheckCircleIcon aria-label="Success" fill="green" />
216
Operation completed
217
</div>
218
219
<div>
220
<AlertIcon aria-label="Warning" fill="orange" />
221
Please review your input
222
</div>
223
224
<div>
225
<XCircleIcon aria-label="Error" fill="red" />
226
Failed to save changes
227
</div>
228
</div>
229
)
230
}
231
```
232
233
## Interactive Icons
234
235
### Button Icons
236
237
When icons function as buttons, provide proper button semantics:
238
239
```jsx
240
import { GearIcon, BellIcon, SearchIcon } from '@primer/octicons-react'
241
242
function IconButtons() {
243
return (
244
<div>
245
{/* Proper button with icon */}
246
<button
247
type="button"
248
aria-label="Open settings"
249
>
250
<GearIcon aria-hidden="true" />
251
</button>
252
253
{/* Icon as button with role */}
254
<GearIcon
255
role="button"
256
tabIndex={0}
257
aria-label="Toggle notifications"
258
onClick={toggleNotifications}
259
onKeyDown={handleButtonKeyDown}
260
/>
261
262
{/* Icon link */}
263
<a href="/search" aria-label="Search">
264
<SearchIcon aria-hidden="true" />
265
</a>
266
</div>
267
)
268
}
269
270
function handleButtonKeyDown(event) {
271
if (event.key === 'Enter' || event.key === ' ') {
272
event.preventDefault()
273
event.target.click()
274
}
275
}
276
```
277
278
## Screen Reader Testing
279
280
### Announcement Patterns
281
282
Different icon usage patterns produce different screen reader announcements:
283
284
```jsx
285
// "button, Add new item"
286
<button>
287
<PlusIcon aria-label="Add new item" />
288
</button>
289
290
// "image, Warning icon"
291
<AlertIcon aria-label="Warning icon" />
292
293
// "Starred repositories" (icon ignored)
294
<span>
295
<StarIcon aria-hidden="true" />
296
Starred repositories
297
</span>
298
299
// "button, Settings, Open user preferences"
300
<button aria-label="Settings" title="Open user preferences">
301
<GearIcon aria-hidden="true" />
302
</button>
303
```
304
305
## Best Practices
306
307
### Labeling Guidelines
308
- Use concise, descriptive labels that explain the icon's purpose
309
- Avoid redundant phrases like "icon" or "image" in labels
310
- Match label tone and terminology with surrounding content
311
- Test labels with actual screen reader users when possible
312
313
### Focus Management
314
315
Icons automatically manage the `focusable` attribute based on the `tabIndex` prop:
316
- When `tabIndex` is undefined (default): `focusable="false"` (prevents assistive technology delays)
317
- When `tabIndex >= 0`: `focusable="true"` (enables keyboard navigation)
318
319
```jsx
320
// Non-focusable (default) - good for decorative icons
321
<AlertIcon aria-hidden="true" />
322
323
// Focusable and interactive
324
<GearIcon
325
tabIndex={0}
326
aria-label="Settings"
327
onClick={openSettings}
328
/>
329
```
330
331
**Best Practices:**
332
- Only make icons focusable when they perform actions
333
- Ensure focused icons have visible focus indicators
334
- Group related interactive icons for efficient navigation
335
- Provide keyboard alternatives for complex icon interactions
336
337
### Color and Contrast
338
- Never rely solely on color to convey information
339
- Ensure icon colors meet WCAG contrast requirements
340
- Provide text alternatives when color indicates status
341
- Test icon visibility in high contrast mode
342
343
### Context and Relationships
344
- Use `aria-labelledby` to connect icons with related headings
345
- Group related icons using appropriate markup (lists, toolbars)
346
- Provide context for standalone icons through surrounding content
347
- Consider icon placement within heading hierarchy
348
349
### Testing Checklist
350
- [ ] Test with screen readers (NVDA, JAWS, VoiceOver)
351
- [ ] Verify keyboard navigation works properly
352
- [ ] Check focus indicators are visible
353
- [ ] Validate ARIA attributes with accessibility tools
354
- [ ] Test in high contrast mode
355
- [ ] Review color contrast ratios
356
- [ ] Verify icons scale appropriately for zoom levels