Swarm Icons

PHP 8.2+

A framework-agnostic PHP library for rendering SVG icons

200,000+ icons from Iconify · Local SVG · JSON collections · No Node.js required

$ composer require frostybee/swarm-icons

Four ways to work with icons

Mix and match providers to suit your project

Download sets once via CLI. Icons are lazy-loaded and PSR-16 cached. Works fully offline after setup.

Offline — no HTTP at runtime
// 1. Download sets once . no Node.js required
// php bin/swarm-icons json:download mdi tabler heroicons

use Frostybee\SwarmIcons\SwarmIcons;
use Frostybee\SwarmIcons\SwarmIconsConfig;

$manager = SwarmIconsConfig::create()
    ->discoverJsonSets()           // auto-register all downloaded sets
    ->cachePath('/var/cache/icons')
    ->build();

SwarmIcons::setManager($manager);

// Render icons anywhere in your PHP app
echo swarm_icon('mdi:home', ['class' => 'w-6 h-6']);
echo swarm_icon('tabler:star', ['aria-label' => 'Favorite']);
echo swarm_icon('heroicons:user');
// 1. Download sets once . no Node.js required
// php bin/swarm-icons json:download mdi tabler heroicons

use Frostybee\SwarmIcons\SwarmIcons;
use Frostybee\SwarmIcons\SwarmIconsConfig;

$manager = SwarmIconsConfig::create()
    ->discoverJsonSets()           // auto-register all downloaded sets
    ->cachePath('/var/cache/icons')
    ->build();

SwarmIcons::setManager($manager);

// Render icons anywhere in your PHP app
echo swarm_icon('mdi:home', ['class' => 'w-6 h-6']);
echo swarm_icon('tabler:star', ['aria-label' => 'Favorite']);
echo swarm_icon('heroicons:user');

Mix providers, set defaults, configure suffix rules, define aliases, and set fallbacks — all in one fluent chain.

Fluent setup API
use Frostybee\SwarmIcons\SwarmIconsConfig;

$manager = SwarmIconsConfig::create()
    ->addIconifySet('heroicons')
    ->addIconifySet('tabler')
    ->addDirectory('custom', __DIR__ . '/resources/icons')
    ->addJsonCollection('mdi', __DIR__ . '/resources/mdi.json')
    ->cachePath('/var/cache/icons')
    ->defaultPrefix('heroicons')
    ->defaultAttributes(['class' => 'icon'])
    ->prefixAttributes('tabler', ['stroke-width' => '1.5'])
    ->prefixSuffix('heroicons', 'solid', ['fill' => 'currentColor'])
    ->prefixSuffix('heroicons', 'outline', ['stroke' => 'currentColor', 'fill' => 'none'])
    ->alias('check', 'heroicons:check-circle')
    ->fallbackIcon('heroicons:question-mark-circle')
    ->ignoreNotFound()
    ->build();
use Frostybee\SwarmIcons\SwarmIconsConfig;

$manager = SwarmIconsConfig::create()
    ->addIconifySet('heroicons')
    ->addIconifySet('tabler')
    ->addDirectory('custom', __DIR__ . '/resources/icons')
    ->addJsonCollection('mdi', __DIR__ . '/resources/mdi.json')
    ->cachePath('/var/cache/icons')
    ->defaultPrefix('heroicons')
    ->defaultAttributes(['class' => 'icon'])
    ->prefixAttributes('tabler', ['stroke-width' => '1.5'])
    ->prefixSuffix('heroicons', 'solid', ['fill' => 'currentColor'])
    ->prefixSuffix('heroicons', 'outline', ['stroke' => 'currentColor', 'fill' => 'none'])
    ->alias('check', 'heroicons:check-circle')
    ->fallbackIcon('heroicons:question-mark-circle')
    ->ignoreNotFound()
    ->build();

Every icon method returns a new instance. Chain size, class, stroke, fill, and custom attributes safely.

Immutable value objects
// Icons are immutable value objects . every method returns a new instance
$icon = $manager->get('heroicons:home');

echo $icon->size(32)->class('text-blue-500');
echo $icon->size(24)->strokeWidth(1.5)->fill('none');

// Fluent chaining
echo $manager->get('tabler:star')
    ->size(20)
    ->class('text-yellow-400')
    ->attr('aria-label', 'Favorite');

// Conditional rendering
if ($manager->has('custom:logo')) {
    echo $manager->get('custom:logo', ['aria-label' => 'Logo']);
}
// Icons are immutable value objects . every method returns a new instance
$icon = $manager->get('heroicons:home');

echo $icon->size(32)->class('text-blue-500');
echo $icon->size(24)->strokeWidth(1.5)->fill('none');

// Fluent chaining
echo $manager->get('tabler:star')
    ->size(20)
    ->class('text-yellow-400')
    ->attr('aria-label', 'Favorite');

// Conditional rendering
if ($manager->has('custom:logo')) {
    echo $manager->get('custom:logo', ['aria-label' => 'Logo']);
}

Dedicated Twig extension with icon(), icon_exists(), and get_icon() functions.

Twig templates
{# Register once in your bootstrap #}
{# $twig->addExtension(new SwarmIconsExtension(...)); #}

{{ icon('heroicons:home') }}
{{ icon('heroicons:user', {class: 'w-6 h-6', 'aria-label': 'Profile'}) }}

{% if icon_exists('custom:logo') %}
    {{ icon('custom:logo') }}
{% endif %}

{# Fluent API via get_icon() #}
{% set star = get_icon('tabler:star') %}
{{ star.size(24).class('text-yellow-400') }}
{# Register once in your bootstrap #}
{# $twig->addExtension(new SwarmIconsExtension(...)); #}

{{ icon('heroicons:home') }}
{{ icon('heroicons:user', {class: 'w-6 h-6', 'aria-label': 'Profile'}) }}

{% if icon_exists('custom:logo') %}
    {{ icon('custom:logo') }}
{% endif %}

{# Fluent API via get_icon() #}
{% set star = get_icon('tabler:star') %}
{{ star.size(24).class('text-yellow-400') }}

Built for PHP developers

200,000+ Icons

Access any of the 200+ Iconify icon sets at runtime or pre-download them for offline use. No Node.js required.

Modern PHP 8.2+

Strict types, fully typed codebase, immutable value objects, PSR-4 autoloading, PHPStan Level 8.

PSR-16 Caching

Bring your own cache or use the built-in file cache. Icons are cached forever by default — zero overhead after first render.

XSS-Safe SVG

Built-in sanitizer strips <script>, on* handlers, javascript: URIs, and external resource references.

Twig & Blade

A dedicated Twig extension with icon(), icon_exists(), and get_icon(). Laravel Blade works via the global helper.

Accessibility Built-in

Decorative icons get aria-hidden="true" automatically. Add aria-label to mark icons as meaningful.