or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

accessibility.mdcustomization.mdicon-components.mdindex.mdstyling.md

accessibility.mddocs/

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