React components for GitHub's Octicons icon library providing scalable SVG icons with tree-shaking support and TypeScript definitions.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
@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.
Icons automatically set aria-hidden and role attributes based on labeling:
aria-label or aria-labelledby is provided: role="img" and aria-hidden is unsetaria-hidden="true" (decorative)interface AriaProps {
/** Accessible label for screen readers */
'aria-label'?: string
/** References element that labels this icon */
'aria-labelledby'?: string
/** Title text for tooltips and additional context */
title?: string | React.ReactElement<any>
}Use aria-label to provide descriptive text for icons that convey meaning:
import { PlusIcon, AlertIcon, CheckIcon } from '@primer/octicons-react'
function AccessibleIcons() {
return (
<div>
<button>
<PlusIcon aria-label="Add new item" />
New
</button>
<div>
<AlertIcon aria-label="Warning: Please review your input" />
Form validation error
</div>
<span>
<CheckIcon aria-label="Task completed successfully" />
Done
</span>
</div>
)
}Use aria-labelledby when an existing element provides the label:
import { PlusIcon, GearIcon } from '@primer/octicons-react'
function LabelledByExample() {
return (
<div>
<h2 id="settings-title">Account Settings</h2>
<GearIcon aria-labelledby="settings-title" />
<button>
<PlusIcon aria-labelledby="add-button-label" title="Create new project" />
<span id="add-button-label">Add Project</span>
</button>
</div>
)
}interface KeyboardProps {
/** Tab order for keyboard navigation */
tabIndex?: number
}Tab Index Values:
0: Include in natural tab order-1: Focusable via JavaScript but not in tab orderundefined (default): Not focusableimport { SearchIcon, CloseIcon } from '@primer/octicons-react'
function InteractiveIcons() {
return (
<div>
{/* Focusable search icon */}
<SearchIcon
aria-label="Open search"
tabIndex={0}
onClick={handleSearch}
onKeyDown={handleKeyDown}
/>
{/* Close button that's keyboard accessible */}
<CloseIcon
aria-label="Close dialog"
tabIndex={0}
role="button"
onClick={handleClose}
onKeyDown={(e) => {
if (e.key === 'Enter' || e.key === ' ') {
handleClose()
}
}}
/>
{/* Decorative icon - not focusable */}
<StarIcon aria-hidden="true" />
</div>
)
}Icons automatically manage ARIA attributes based on provided props:
interface AutoAriaProps {
/** Automatically set based on other props */
'aria-hidden'?: 'true' | undefined
/** Automatically set when aria-label or aria-labelledby provided */
role?: 'img' | undefined
/** Controlled by tabIndex prop */
focusable?: 'true' | 'false'
}Automatic Behavior:
aria-hidden="true" when no accessibility props providedrole="img" when aria-label or aria-labelledby providedfocusable="false" when tabIndex is undefined or negativefocusable="true" when tabIndex is 0 or positiveThe title prop creates an SVG <title> element for additional context:
import { InfoIcon, WarningIcon } from '@primer/octicons-react'
function TitledIcons() {
return (
<div>
<InfoIcon
title="Additional information available"
aria-label="Information"
/>
<WarningIcon
title="This action cannot be undone"
aria-label="Warning"
/>
</div>
)
}Icons that don't convey unique information should be hidden from screen readers:
import { StarIcon, HeartIcon } from '@primer/octicons-react'
function DecorativeIcons() {
return (
<div>
{/* Text already conveys the meaning */}
<span>
<StarIcon aria-hidden="true" />
Starred Repository
</span>
{/* Icon is purely visual decoration */}
<h1>
<HeartIcon aria-hidden="true" />
Favorite Projects
</h1>
</div>
)
}Icons that convey important information need accessibility attributes:
import { AlertIcon, CheckCircleIcon, XCircleIcon } from '@primer/octicons-react'
function SemanticIcons() {
return (
<div>
{/* Status indicators */}
<div>
<CheckCircleIcon aria-label="Success" fill="green" />
Operation completed
</div>
<div>
<AlertIcon aria-label="Warning" fill="orange" />
Please review your input
</div>
<div>
<XCircleIcon aria-label="Error" fill="red" />
Failed to save changes
</div>
</div>
)
}When icons function as buttons, provide proper button semantics:
import { GearIcon, BellIcon, SearchIcon } from '@primer/octicons-react'
function IconButtons() {
return (
<div>
{/* Proper button with icon */}
<button
type="button"
aria-label="Open settings"
>
<GearIcon aria-hidden="true" />
</button>
{/* Icon as button with role */}
<GearIcon
role="button"
tabIndex={0}
aria-label="Toggle notifications"
onClick={toggleNotifications}
onKeyDown={handleButtonKeyDown}
/>
{/* Icon link */}
<a href="/search" aria-label="Search">
<SearchIcon aria-hidden="true" />
</a>
</div>
)
}
function handleButtonKeyDown(event) {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault()
event.target.click()
}
}Different icon usage patterns produce different screen reader announcements:
// "button, Add new item"
<button>
<PlusIcon aria-label="Add new item" />
</button>
// "image, Warning icon"
<AlertIcon aria-label="Warning icon" />
// "Starred repositories" (icon ignored)
<span>
<StarIcon aria-hidden="true" />
Starred repositories
</span>
// "button, Settings, Open user preferences"
<button aria-label="Settings" title="Open user preferences">
<GearIcon aria-hidden="true" />
</button>Icons automatically manage the focusable attribute based on the tabIndex prop:
tabIndex is undefined (default): focusable="false" (prevents assistive technology delays)tabIndex >= 0: focusable="true" (enables keyboard navigation)// Non-focusable (default) - good for decorative icons
<AlertIcon aria-hidden="true" />
// Focusable and interactive
<GearIcon
tabIndex={0}
aria-label="Settings"
onClick={openSettings}
/>Best Practices:
aria-labelledby to connect icons with related headingsInstall with Tessl CLI
npx tessl i tessl/npm-primer--octicons-react