SVG Icon Naming Conventions for Design Systems

How to name SVG icons consistently across Figma, code, and documentation, comparing Lucide, Tabler, and Material naming systems with a practical framework for your own design system.

Amit Yadav
Amit Yadav

Icon names are the invisible infrastructure of a design system. A well-named icon is findable in search, predictable in autocomplete, and self-documenting in code. A poorly named icon gets duplicated, misused, and quietly abandoned. Most naming problems don’t surface until you have 200+ icons and no one can remember if the “arrow-right” or “chevron-right” is the navigation icon.

This guide compares the naming strategies of three production systems, identifies their tradeoffs, and gives you a practical naming framework to apply immediately.

Why naming matters at scale

At 20 icons, names barely matter, you remember them all. At 200, you need a system. At 2,000, a bad system causes:

  • Duplicate icons under different names (arrow-forward and arrow-right)
  • Wrong icon used because search returns multiple similar results
  • Inconsistent imports (SearchIcon in one file, IconSearch in another)
  • Broken refactors when icons are renamed after the fact

These six icons all “point right”, without a consistent naming convention, teams end up using them interchangeably and inconsistently.

The three major naming systems

System 1: Lucide: verb-noun / noun (kebab-case)

Lucide uses lowercase kebab-case with a descriptive name. Action icons use a verb, object icons use a noun, and compound icons combine them:

search           → noun
settings         → noun (not "gear" or "cog")
arrow-right      → noun + direction
file-text        → compound noun
alert-triangle   → noun + shape modifier
layout-dashboard → compound noun (context + component)

Strengths: Human-readable, matches plain English description, works well in search.

Weaknesses: No enforced prefix, Icon must be added in import statements. Some names are opinionated (settings vs gear).

System 2: Tabler: Icon prefix + PascalCase

Tabler appends Icon as a prefix to every exported component name:

IconSearch         → Icon + Search
IconLayoutDashboard → Icon + compound descriptor
IconAlertTriangle  → Icon + compound descriptor
IconArrowRight     → Icon + compound descriptor

Strengths: Impossible to confuse icons with non-icon components in autocomplete. All icons surface together when you type Icon.

Weaknesses: Verbose. IconLayoutDashboard is long. The Icon prefix is redundant when your IDE already has type info.

System 3: Material Symbols: snake_case with _outline / _filled suffixes

Google’s Material Symbols uses snake_case names with optional suffixes for variants:

search
search_outlined
settings
notifications
notifications_outlined
notifications_active

Strengths: Maps directly to the CSS variable system used for variable fonts. Variant suffixes are consistent.

Weaknesses: Doesn’t work well as TypeScript identifiers (underscores aren’t conventional in React component names). The filled/outlined distinction requires renaming between variants.

A practical naming framework

For a new design system, this hybrid framework combines the best parts of each:

Rule 1: kebab-case file names, PascalCase component names

assets/icons/search.svg         → SearchIcon (component)
assets/icons/arrow-right.svg    → ArrowRightIcon (component)
assets/icons/file-text.svg      → FileTextIcon (component)

The Icon suffix in the component name prevents collisions with non-icon components:

// Unambiguous, you know this is an SVG icon
import { SearchIcon, FileTextIcon } from '@/components/icons';

// Ambiguous, is SearchButton a button or an icon?
import { Search } from '@/components/icons';
Suffix vs prefix: suffix wins in autocomplete

SearchIcon, SettingsIcon, BellIcon, all surface in autocomplete when you type the noun (Search, Settings, Bell). With IconSearch prefix, you have to type Icon first, which is rarely how developers think of icons.

Rule 2: Noun-first, direction/modifier second

arrow-right     ✅  (noun: arrow, modifier: direction)
right-arrow     ❌  (modifier first, harder to group in sorted lists)

bell-dot        ✅  (noun: bell, modifier: has-dot)
notification    ❌  (semantic alias, different from visual name)

chart-bar       ✅  (noun: chart, modifier: type)
bar-chart       ❌  (inverts standard sort grouping)

Noun-first means all variants of an icon group together alphabetically:

arrow-down
arrow-left
arrow-right
arrow-up
arrow-up-circle
arrow-up-right

Rule 3: Visual names, not semantic names

Name the icon for what it looks like, not what it means in your product:

gear           ✅  (visual: a gear shape)
settings       ⚠️  (semantic: what the gear means in your product)
configuration  ❌  (product-specific term)

Visual names are portable, they work in every product context. Semantic names lock the icon to one use case: a settings icon used for “preferences” feels wrong; a gear icon doesn’t.

Exception: Universally recognized semantic icons are fine: home, search, close, menu. These visual forms are so strongly associated with their meaning that the semantic name is the right choice.

Rule 4: Use a size/weight suffix for multi-variant libraries

heart-16        → 16px optimized variant
heart           → default (24px)
heart-32        → 32px variant

heart           → default weight
heart-bold      → bold weight
heart-duotone   → duotone variant

This makes variant selection clear without inspecting the component:

import { HeartIcon, HeartDuotoneIcon } from '@/components/icons';

Rule 5: Document semantic aliases separately

Rather than naming icons semantically, create a semantic alias layer:

// src/components/icons/semantic.ts
// Maps product concepts to visual icons
export { GearIcon as SettingsIcon } from './index';
export { BellIcon as NotificationsIcon } from './index';
export { PersonIcon as ProfileIcon } from './index';
export { LayoutDashboardIcon as DashboardIcon } from './index';

Developers can use semantic names in product code while the icon library remains visually named:

// Product code, uses semantic names
import { SettingsIcon, NotificationsIcon } from '@/components/icons/semantic';

// Icon library code, uses visual names
import { GearIcon, BellIcon } from '@/components/icons';

Naming for searchability

Icon search (both in design tools and code editors), relies on names. Test your naming system with these search queries:

Developer thinks…Should find…
“delete”TrashIcon (needs alias: DeleteIcon = TrashIcon)
“close”XIcon or CloseIcon
”loading”LoaderIcon or SpinnerIcon
”warning”AlertTriangleIcon
”info”InfoCircleIcon or InfoIcon
”check”CheckIcon
”link”LinkIcon or ExternalLinkIcon

Build a search-alias map for common conceptual mismatches:

// src/components/icons/aliases.ts
export { TrashIcon as DeleteIcon } from './index';
export { XIcon as CloseIcon } from './index';
export { Loader2Icon as SpinnerIcon } from './index';
export { AlertTriangleIcon as WarningIcon } from './index';
Add aliases, never rename

Renaming an icon breaks every import in every component. When you discover a name mismatch (developers keep searching for “close” but the icon is named XIcon), add an alias rather than renaming. Aliases are additive; renames are destructive.

Documenting your icon vocabulary

A naming convention only works if it’s documented and enforced. The minimum documentation:

1. A naming guide (one page in your design system docs):

  • The case format (kebab-case files, PascalCase components)
  • Noun-first rule with examples
  • The visual-name policy with exception list
  • How to request a new icon

2. An icon inventory (searchable table of all icons):

  • Visual name, semantic aliases, Figma component name, React import name
  • Helps identify duplicates before they proliferate

3. Lint rules (optional but powerful):

// .eslintrc, custom rule: icons must have Icon suffix
'local-rules/icon-naming': ['error', { suffix: 'Icon' }]

Migrating a legacy naming system

If your codebase already has inconsistent icon names, migrate gradually:

  1. Add the Icon suffix as aliases first: export { Search as SearchIcon }
  2. Update new code to use the new names
  3. Run a codemod to migrate existing usage: jscodeshift --transform=icon-rename src/
  4. Remove the old aliases in a major version bump

Never do a big-bang rename. It creates a massive PR, breaks git blame, and introduces merge conflicts across every feature branch.

Share this post