Skip to content

SVG Sprite Icon System Guide

Complete guide to using SVG sprites for optimal icon management across multiple projects.

Why SVG Sprites?

SVG sprites are the optimal approach for managing icons:

Performance Benefits

  • Single HTTP Request - One request per sprite file (vs. one per icon)
  • Better Caching - Browser caches the entire sprite
  • Smaller Total Size - Shared definitions reduce file size
  • Faster Page Loads - Fewer network requests

Build Benefits

  • No Build Processing - Icons are static files
  • Zero Build Impact - Adding icons doesn't slow builds
  • No Bundling - Icons aren't bundled into JavaScript
  • Easy Updates - Just edit SVG file, refresh browser

Maintenance Benefits

  • Version Control Friendly - Single file per icon set
  • CDN Compatible - Can be served from CDN
  • Framework Agnostic - Works with any framework
  • Easy Collaboration - Designers can edit SVG directly

Architecture

Library Level (Common Icons)

packages/ui/src/icons/
└── common-icons.svg  (only icons used across multiple projects)

Project Level (Project Icons)

your-project/
└── public/
    └── svg-icons.svg  (all project-specific icons)

Sprite File Structure

A sprite file contains multiple icon definitions as <symbol> elements:

svg
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <!-- Icon 1 -->
    <symbol id="icon-name-1" viewBox="0 0 24 24" fill="none">
      <path d="..." fill="currentColor"/>
    </symbol>
    
    <!-- Icon 2 -->
    <symbol id="icon-name-2" viewBox="0 0 24 24" fill="none">
      <path d="..." stroke="currentColor" stroke-width="2"/>
    </symbol>
  </defs>
</svg>

Key Points

  • Each icon is a <symbol> element
  • id attribute is the icon name
  • viewBox defines the coordinate system
  • Use currentColor for fill/stroke (allows color customization)

Setup

1. Create Project Sprite File

Create public/svg-icons.svg:

svg
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <symbol id="project-dashboard" viewBox="0 0 24 24" fill="none">
      <path d="M3 3h18v18H3V3z" stroke="currentColor" stroke-width="2"/>
    </symbol>
  </defs>
</svg>

2. Register Sprite

In main.js:

javascript
import { registerSprite } from '@ftx/ui';

// Register project sprite (no prefix for project icons)
registerSprite('/svg-icons.svg', {
  prefix: '', // No prefix - these are project icons
  priority: 20
});

3. Use Icons

vue
<!-- Project icon (no prefix needed) -->
<FTxIcon name="dashboard" svg-size="24px" />

Multiple Sprite Sources

Register multiple sprites for different icon sets:

javascript
import { registerSprite } from '@ftx/ui';

// Common icons (highest priority)
registerSprite('/icons/common-icons.svg', {
  prefix: 'ftx-',
  priority: 10
});

// Navigation icons
registerSprite('/icons/nav-icons.svg', {
  prefix: 'nav-',
  priority: 20
});

// Project icons (default)
registerSprite('/svg-icons.svg', {
  priority: 30
});

Priority System

  • Lower priority number = higher priority
  • Component searches sprites in priority order
  • First matching sprite is used

Adding Icons

Adding to Project Sprite

  1. Edit sprite file:

    svg
    <symbol id="my-new-icon" viewBox="0 0 24 24" fill="none">
      <path d="..." fill="currentColor"/>
    </symbol>
  2. Save file

  3. Refresh browser - icon is immediately available!

No build needed!

Adding to Common Sprite (Library)

Important: Common icons are stored ONLY in the common-icons.svg sprite file. Individual SVG files are not used for common icons.

  1. Edit packages/ui/src/icons/common-icons.svg
  2. Add a new <symbol> element with ftx- prefix:
svg
<symbol id="ftx-new-icon" viewBox="0 0 24 24" fill="none">
  <path d="..." stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</symbol>

Key points:

  • Use <symbol> element (not <svg>)
  • id attribute must match icon name (e.g., ftx-new-icon)
  • Use currentColor for fill/stroke
  • Include viewBox attribute (typically 0 0 24 24)
  1. Rebuild library
  2. The sprite file will be included in the distribution

Note: The icon-registry.js file is for project-specific icons registered dynamically. Common library icons are served via the sprite file only.

Best Practices

1. Icon Naming

  • Library icons: Use ftx- prefix in sprite files (internal format). When using icons, use ftx: prefix format (e.g., ftx:column)
  • Project icons: No prefix needed in sprite files (e.g., dashboard, settings)
  • Use kebab-case: dashboard, nav-settings, ftx-column
  • Avoid conflicts between library and project icons

Important:

  • Library icons (ftx:) are always in sprite files with ftx- prefix
  • Project icons (no prefix) can be in sprite files OR registered via registerIcon()
  • Icons registered via registerIcon() take priority over sprite files

2. SVG Optimization

  • Use currentColor for fill/stroke
  • Include viewBox attribute
  • Remove unnecessary attributes
  • Optimize paths
  • Use consistent viewBox (e.g., 0 0 24 24)

3. Sprite Organization

Option 1: Single Sprite (Recommended for Small Projects)

public/svg-icons.svg  (all project icons)

Option 2: Multiple Sprites (Recommended for Large Projects)

public/
├── nav-icons.svg      (navigation icons)
├── action-icons.svg   (action buttons)
├── status-icons.svg   (status indicators)
└── svg-icons.svg      (general icons)

4. Color Customization

Always use currentColor:

svg
<!-- Good -->
<symbol id="icon" viewBox="0 0 24 24" fill="none">
  <path d="..." fill="currentColor"/>
</symbol>

<!-- Bad -->
<symbol id="icon" viewBox="0 0 24 24">
  <path d="..." fill="#000000"/>
</symbol>

Then customize in component:

vue
<FTxIcon name="icon" svg-size="24px" svg-color="#1976d2" />

Performance Comparison

ApproachHTTP RequestsBundle SizeBuild TimeCache
Individual SVGsN iconsLargeSlowPoor
Inline SVGs0LargeSlowN/A
SVG Sprites1-2SmallNoneExcellent

Troubleshooting

Icon Not Showing

  1. Check sprite file is accessible:

    • Open /svg-icons.svg in browser
    • Verify it's in public folder
  2. Verify symbol ID:

    svg
    <symbol id="my-icon" ...>  <!-- Must match name="my-icon" -->
  3. Check sprite registration:

    javascript
    import { getSpriteSources } from '@ftx/ui';
    console.log(getSpriteSources());

Icon Color Not Changing

  • Ensure SVG uses currentColor
  • Use svg-color prop (not color)

Multiple Sprites Not Working

  • Check priority order
  • Verify icon name matches symbol ID
  • Use sprite-path prop to force specific sprite

Advanced Usage

Custom Sprite Path

Override sprite lookup:

vue
<FTxIcon 
  name="custom-icon" 
  svg-size="24px"
  sprite-path="/custom-icons.svg"
/>

Disable Sprite (Use Inline)

vue
<FTxIcon 
  name="ftx:icon" 
  svg-size="24px"
  :use-sprite="false"
/>

Migration from Other Approaches

From Individual SVG Files

  1. Combine all SVGs into one sprite file
  2. Convert each SVG to a <symbol> element
  3. Register sprite
  4. Update component usage

From Inline SVGs

  1. Extract SVG content
  2. Add to sprite as <symbol>
  3. Register sprite
  4. Use FTxIcon component

Released under the MIT License.