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 icons support extensive customization through standard React props, CSS styling, and integration with popular styling libraries. Icons inherit all standard SVG element properties while providing convenient abstractions for common customizations.
Icons inherit all standard SVG element properties, enabling full customization:
interface CustomizationProps extends React.ComponentPropsWithoutRef<'svg'> {
/** CSS class names for styling */
className?: string
/** Inline styles */
style?: React.CSSProperties
/** Fill color (defaults to currentColor) */
fill?: string
/** Unique identifier */
id?: string
/** Mouse event handlers */
onClick?: React.MouseEventHandler<SVGSVGElement>
onMouseEnter?: React.MouseEventHandler<SVGSVGElement>
onMouseLeave?: React.MouseEventHandler<SVGSVGElement>
onMouseDown?: React.MouseEventHandler<SVGSVGElement>
onMouseUp?: React.MouseEventHandler<SVGSVGElement>
/** Focus event handlers */
onFocus?: React.FocusEventHandler<SVGSVGElement>
onBlur?: React.FocusEventHandler<SVGSVGElement>
/** Keyboard event handlers */
onKeyDown?: React.KeyboardEventHandler<SVGSVGElement>
onKeyUp?: React.KeyboardEventHandler<SVGSVGElement>
/** All other standard SVG element props are supported */
}Icons support all standard SVG event handlers for interactive functionality:
import { GearIcon, BellIcon, ThumbsupIcon } from '@primer/octicons-react'
function InteractiveIcons() {
const [isHovered, setIsHovered] = useState(false)
const [isPressed, setIsPressed] = useState(false)
return (
<div>
{/* Click handler */}
<GearIcon
onClick={() => console.log('Settings clicked')}
style={{ cursor: 'pointer' }}
aria-label="Settings"
/>
{/* Hover effects */}
<BellIcon
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
fill={isHovered ? '#0969da' : 'currentColor'}
aria-label="Notifications"
/>
{/* Press states */}
<ThumbsupIcon
onMouseDown={() => setIsPressed(true)}
onMouseUp={() => setIsPressed(false)}
onMouseLeave={() => setIsPressed(false)}
style={{
transform: isPressed ? 'scale(0.9)' : 'scale(1)',
transition: 'transform 0.1s'
}}
aria-label="Like"
/>
</div>
)
}import { SearchIcon } from '@primer/octicons-react'
function KeyboardInteractiveIcon({ onActivate }) {
const handleKeyDown = (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault()
onActivate()
}
}
return (
<SearchIcon
tabIndex={0}
onKeyDown={handleKeyDown}
onClick={onActivate}
aria-label="Search"
style={{ cursor: 'pointer' }}
/>
)
}import { RocketIcon, StarIcon } from '@primer/octicons-react'
function ClassStyledIcons() {
return (
<div>
<RocketIcon className="icon-primary" />
<StarIcon className="icon-secondary icon-animated" />
</div>
)
}.icon-primary {
color: #0969da;
cursor: pointer;
transition: color 0.2s ease;
}
.icon-primary:hover {
color: #0550ae;
}
.icon-secondary {
color: #656d76;
opacity: 0.8;
}
.icon-animated {
transition: transform 0.2s ease;
}
.icon-animated:hover {
transform: scale(1.1);
}import { GearIcon, BellIcon } from '@primer/octicons-react'
function InlineStyledIcons() {
const iconStyle = {
color: '#ff6b6b',
cursor: 'pointer',
transition: 'all 0.3s ease',
filter: 'drop-shadow(0 2px 4px rgba(0,0,0,0.1))'
}
return (
<div>
<GearIcon style={iconStyle} />
<BellIcon
style={{
color: 'var(--color-accent)',
marginLeft: '8px',
transform: 'rotate(15deg)'
}}
/>
</div>
)
}import styled from 'styled-components'
import { SearchIcon, FilterIcon } from '@primer/octicons-react'
const PrimaryIcon = styled(SearchIcon)`
color: ${props => props.theme.primary};
cursor: pointer;
transition: all 0.2s ease;
&:hover {
color: ${props => props.theme.primaryHover};
transform: scale(1.05);
}
&:active {
transform: scale(0.95);
}
`
const ToolbarIcon = styled(FilterIcon)`
padding: 8px;
border-radius: 4px;
background: ${props => props.active ? props.theme.activeBg : 'transparent'};
&:hover {
background: ${props => props.theme.hoverBg};
}
`
function StyledComponentIcons({ isFilterActive }) {
return (
<div>
<PrimaryIcon size="medium" />
<ToolbarIcon active={isFilterActive} size="small" />
</div>
)
}import { css } from '@emotion/react'
import { HeartIcon, StarIcon } from '@primer/octicons-react'
const heartIconStyle = css`
color: #e74c3c;
cursor: pointer;
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
&:hover {
color: #c0392b;
transform: scale(1.2);
}
&:active {
transform: scale(0.9);
}
`
const pulsingStyle = css`
animation: pulse 2s infinite;
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
`
function EmotionStyledIcons() {
return (
<div>
<HeartIcon css={heartIconStyle} />
<StarIcon css={[heartIconStyle, pulsingStyle]} />
</div>
)
}import { CodeIcon, BranchIcon } from '@primer/octicons-react'
function DesignSystemIcons() {
return (
<div>
<CodeIcon
style={{
color: 'var(--color-icon-primary)',
width: 'var(--size-icon-medium)',
height: 'var(--size-icon-medium)',
margin: 'var(--spacing-xs)'
}}
/>
<BranchIcon
className="ds-icon"
fill="var(--color-success)"
/>
</div>
)
}:root {
--color-icon-primary: #24292f;
--color-icon-secondary: #656d76;
--size-icon-small: 16px;
--size-icon-medium: 20px;
--size-icon-large: 24px;
--spacing-xs: 4px;
}
.ds-icon {
width: var(--size-icon-medium);
height: var(--size-icon-medium);
}import React, { useContext } from 'react'
import { ThemeContext } from './ThemeProvider'
import { MoonIcon, SunIcon } from '@primer/octicons-react'
function ThemedIcon() {
const theme = useContext(ThemeContext)
const iconProps = {
fill: theme.colors.icon.primary,
style: {
transition: 'fill 0.2s ease',
cursor: 'pointer'
}
}
return theme.mode === 'dark' ?
<SunIcon {...iconProps} /> :
<MoonIcon {...iconProps} />
}import { AlertIcon, CheckIcon } from '@primer/octicons-react'
function CustomIconVariants() {
const createVariant = (Component, baseProps) => (props) => (
<Component {...baseProps} {...props} />
)
const DangerIcon = createVariant(AlertIcon, {
fill: '#d1242f',
'aria-label': 'Danger'
})
const SuccessIcon = createVariant(CheckIcon, {
fill: '#1a7f37',
'aria-label': 'Success'
})
return (
<div>
<DangerIcon size="medium" />
<SuccessIcon size="medium" />
</div>
)
}import { RepoIcon, LockIcon } from '@primer/octicons-react'
function CompositeIcon({ isPrivate, size = 'medium' }) {
return (
<div style={{ position: 'relative', display: 'inline-block' }}>
<RepoIcon size={size} />
{isPrivate && (
<LockIcon
size="small"
style={{
position: 'absolute',
bottom: -2,
right: -2,
background: 'white',
borderRadius: '50%',
padding: 1
}}
/>
)}
</div>
)
}import { SyncIcon, SpinnerIcon } from '@primer/octicons-react'
function AnimatedIcons() {
return (
<div>
{/* Rotation animation */}
<SyncIcon
className="rotating"
style={{
animation: 'rotate 1s linear infinite'
}}
/>
{/* Fade in/out */}
<StarIcon
style={{
animation: 'fadeInOut 2s ease-in-out infinite'
}}
/>
{/* Bounce effect */}
<HeartIcon
className="bouncing"
onClick={handleLike}
/>
</div>
)
}@keyframes rotate {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes fadeInOut {
0%, 100% { opacity: 1; }
50% { opacity: 0.3; }
}
.bouncing:active {
animation: bounce 0.3s ease;
}
@keyframes bounce {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.3); }
}import { MenuIcon } from '@primer/octicons-react'
function ResponsiveIcon() {
return (
<MenuIcon
className="responsive-icon"
style={{
width: 'clamp(16px, 2.5vw, 24px)',
height: 'auto'
}}
/>
)
}.responsive-icon {
transition: width 0.2s ease;
}
@media (max-width: 768px) {
.responsive-icon {
width: 20px !important;
}
}
@media (min-width: 1200px) {
.responsive-icon {
width: 28px !important;
}
}import { SearchIcon } from '@primer/octicons-react'
function ContainerAwareIcon() {
return (
<div className="icon-container">
<SearchIcon className="container-icon" />
</div>
)
}.icon-container {
container-type: inline-size;
}
.container-icon {
width: 16px;
}
@container (min-width: 200px) {
.container-icon {
width: 20px;
}
}
@container (min-width: 400px) {
.container-icon {
width: 24px;
}
}/* Optimize for frequent repaints */
.icon-optimized {
will-change: transform;
transform: translateZ(0); /* Force hardware acceleration */
}
/* Reduce layout thrashing */
.icon-stable {
contain: layout style paint;
}
/* Optimize hover states */
.icon-hover {
transition: transform 0.15s ease;
}
.icon-hover:hover {
transform: scale(1.05);
}Icons support tree-shaking, so only import what you need:
// ✅ Good - Only imports specific icons
import {
AlertIcon,
CheckIcon,
InfoIcon
} from '@primer/octicons-react'
// ❌ Bad - Imports entire library
import * as Octicons from '@primer/octicons-react'Install with Tessl CLI
npx tessl i tessl/npm-primer--octicons-react