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