" /> " /> "/>

A package to easily make use of SVG icons in your Laravel Blade views.

Overview

Blade Icons

Tests Code Style Latest Stable Version Total Downloads

A package to easily make use of SVG icons in your Laravel Blade views. Originally "Blade SVG" by Adam Wathan.

Turn...

<!-- camera.svg -->
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" class="w-6 h-6">
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 9a2 2 0 012-2h.93a2 2 0 001.664-.89l.812-1.22A2 2 0 0110.07 4h3.86a2 2 0 011.664.89l.812 1.22A2 2 0 0018.07 7H19a2 2 0 012 2v9a2 2 0 01-2 2H5a2 2 0 01-2-2V9z"/>
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 13a3 3 0 11-6 0 3 3 0 016 0z"/>
</svg>

Into...

<x-icon-camera class="w-6 h-6" />

Or into...

@svg('camera', 'w-6 h-6')

Looking for a specific icon? Try our icon search: https://blade-ui-kit.com/blade-icons#search

Join the Discord server: https://discord.gg/Vev5CyE

Icon Packages

Blade Icons is a base package to make it easy for you to use SVG icons in your app. In addition, there's also quite some third party icon set packages. Thanks to the community for contributing these!

We're not accepting requests to build new icon packages ourselves but you can start building your own.

Requirements

  • PHP 7.4 or higher
  • Laravel 8.0 or higher

Installation

Install the package with composer:

composer require blade-ui-kit/blade-icons

Then, publish the configuration and uncomment the default icon set:

php artisan vendor:publish --tag=blade-icons

Make sure that the path defined for this icon set exists. By default it's resources/svg. Your SVG icons will need to be placed in this directory.

Upgrading

Please refer to the upgrade guide when upgrading the library.

Caching

When working with Blade Icons, and third party icon sets in particularly, you'll often be working with large icon sets. This can slow down your app tremendously, especially when making use of Blade components. To solve this issue, Blade Icons ships with caching support. To enable icon caching you can run the following command:

php artisan icons:cache

This will create a blade-icons.php file in bootstrap/cache similar to the packages.php cached file. It'll contain a manifest of all known sets and icons with their path locations.

Caching icons means you won't be able to add extra icons, change paths for icon sets or install/remove icon packages. To do so make sure you first clear the icons cache and cache after you've made these changes:

php artisan icons:clear

It's a good idea to add the icons:cache command as part of your deployment pipeline and always cache icons in production.

Alternatively, you may choose to disable Blade components entirely.

Configuration

Defining Sets

Blade Icons support multiple sets. You can define these by passing a key/value combination in the blade-icons.php config file's sets setting:

<?php

return [
    'sets' => [
        'default' => [
            'path' => 'resources/svg',
        ],
    ],
];

Feel free to add as many sets as you wish. Blade Icons ships with a default set for your app which you may adjust to your liking.

Icon Paths

If you wanted to add icons from a different directory in your app, say resources/images/svg, you can set it like this:

<?php

return [
    'sets' => [
        'default' => [
            'path' => 'resources/images/svg',
        ],
    ],
];

⚠️ Always make sure you're pointing to existing directories.

Multiple Paths

In addition to a single path, you may define multiple paths for a single set with the paths option instead:

<?php

return [
    'sets' => [
        'default' => [
            'paths' => [
                'resources/images/icon-set',
                'resources/images/other-icon-set',
            ],
        ],
    ],
];

This gives you the benefit from grouping icons from different paths under a single set where you can define the same prefix and default classes.

⚠️ When using multiple paths instead of one, Blade Icons will return the first icon it finds when an icon name is present in more than one path. Please ensure you use unique icon names when registering multiple paths if you want to retrieve the correct icon.

Filesystem Disk

If you host your icons on an external filesystem storage you can set the disk option for an icon set to a disk defined in your filesystems.php config file. For example, you might store your icons on an AWS S3 bucket which is set in your filesystems.php config file with a disk key of s3-icons:

<?php

return [
    'sets' => [
        'default' => [
            'path' => '/',
            'disk' => 's3-icons',
        ],
    ],
];

And from now on our default set will pull the icons from the S3 bucket. Also notice we've adjusted the path to / because we store our icons in the root directory of this S3 bucket. If you have several icon sets uploaded to the same disk you can set your paths accordingly:

<?php

return [
    'sets' => [
        'heroicons' => [
            'path' => 'heroicons',
            'disk' => 's3-icons',
            'prefix' => 'heroicon',
        ],
        'zondicons' => [
            'path' => 'zondicons',
            'disk' => 's3-icons',
            'prefix' => 'zondicon',
        ],
    ],
];

Fallback Icons

If you want to provide a fallback icon when an icon cannot be found, you may define the fallback option on a specific set:

<?php

return [
    'sets' => [
        'default' => [
            'fallback' => 'cake',
        ],
    ],
];

Now when you try to resolve a non-existing icon for the default icon set, it'll return the rendered "cake" icon instead.

You can also provide a global fallback icon instead. This icon will be used when an icon cannot be found and the set doesn't have its own fallback icon defined. It can reference any icon from any registered icon set.

<?php

return [
    'fallback' => 'heroicon-cake',
];

⚠️ There's one caveat when using fallback icons and that is that they don't work when using Blade Components. In this case, Laravel will throw an exception that the component cannot be found. If you want to make use of fallback icons please consider one of the other usages.

Prefixing Icons

In the default icon set the icon prefix will be applied to every icon, but you're free to adjust this in the blade-icons.php config file:

<?php

return [
    'sets' => [
        'default' => [
            'prefix' => 'icon',
        ],
    ],
];

Defining a prefix for every set is required and every prefix should be unique.

When referencing icons with the Blade directive or helper you can omit the prefix to reference icons from the default set. When referencing icons from other sets, using the prefix is required.

When an icon in the default set has a name which collides with a prefix from a set then the icon from the default set is retrieved first.

Please note that it's best practice that your icons themselves do not have the prefix in their name. So if you have a prefix in your set called icon and your icons are named icon-example.svg you should rename them to example.svg. Otherwise you can run into unexpected name resolving issues.

It's also important to note that icon prefixes cannot contain dashes (-) as this is the delimiter which we use to split it from the rest of the icon name.

Default Classes

You can optionally define classes which will be applied to every icon by filling in the class setting in your blade-icons.php config file:

<?php

return [
    'class' => 'icon icon-default',
];

If you don't want any classes to be applied by default then leave this as an empty string. Additionally, the same option is available in sets so you can set default classes on every set.

The sequence in which classes get applied is <global classes> <set classes> <explicit classes>. You can always override this by passing an explicit class with your attributes. Component classes cannot be overridden.

Default Attributes

You can also optionally define some attributes which will be added to every icon in the attributes setting of your blade-icons.php config file:

<?php

return [
    'attributes' => [
        'width' => 50,
        'height' => 50,
    ],
];

This always needs to be an associative array. Additionally, the same option is available in sets so you can set default attributes on every set.

It is not possible to overwrite existing attributes on SVG icons. If you already have attributes defined on icons which you want to override, remove them first.

Usage

There are several ways of inserting icons into your Blade templates. We personally recommend using Blade components, but you can also make use of a Blade directive if you wish.

Components

The easiest way to get started with using icons from sets are Blade components:

<x-icon-camera/>

Icons in subdirectories can be referenced using dot notation:

<x-icon-solid.camera/>

You can also pass classes to your icon components (default classes will be applied as well):

<x-icon-camera class="icon-lg"/>

Or any other attributes for that matter:

<x-icon-camera class="icon-lg" id="settings-icon" style="color: #555" data-baz/>

⚠️ Note that with Blade components, using a prefix is always required, even when referencing icons from the default set.

Default Component

If you don't want to use the component syntax from above you can also make use of the default Icon component that ships with Blade Icons. Simply pass the icon name through the $name attribute:

<x-icon name="camera"/>

If you want to use a different name for this component instead you can customize the components.default option in your blade-icons.php config file:

<?php

return [
    'components' => [
        'default' => 'svg',
    ],
];

Then reference the default icon as follow:

<x-svg name="camera"/>

You can also completely disable this default component if you want by setting its name to null:

<?php

return [
    'components' => [
        'default' => null,
    ],
];

Disabling Components

Although they're enabled by default, if you don't wish to use components at all you may choose to disable them completely by setting the components.disabled setting in your blade-icons.php config file to true:

<?php

return [
    'components' => [
        'disabled' => true,
    ],
];

Doing this makes sense when you're only using the directive or the helper and can improve overall performance.

Directive

If components aren't really your thing you can make use of the Blade directive instead. If you defined a default icon class in your config and want to render a camera icon with an icon-lg class you can do that like so:

@svg('camera', 'icon-lg')

Any additionally attributes can be passed as a third array argument, and they'll be rendered on the svg element:

@svg('camera', 'icon-lg', ['id' => 'settings-icon'])

If you don't have a class to be defined you can also pass these attributes as the second parameter:

@svg('camera', ['id' => 'settings-icon'])

If you want to override the default classes, pass in the class as an attribute:

@svg('camera', ['class' => 'icon-lg'])

Attributes without a key, are supported too:

@svg('camera', ['data-foo'])

Helper

If you'd like, you can use the svg helper to expose a fluent syntax for setting SVG attributes:

{{ svg('camera')->id('settings-icon')->dataFoo('bar')->dataBaz() }}

Building Packages

If you're interested in building your own third party package to integrate an icon set, it's pretty easy to do so. We've created a template repo for you to get started with. You can find the getting started instructions in its readme.

If you want to learn how to create packages we can recommend these two excellent courses:

Make sure to load your SVGs from the register method of your package's service provider. Provide the path to your SVGs and provide your own unique set name and component prefix:

use BladeUI\Icons\Factory;

public function register(): void
{
    $this->callAfterResolving(Factory::class, function (Factory $factory) {
        $factory->add('heroicons', [
            'path' => __DIR__.'/../resources/svg',
            'prefix' => 'heroicon',
        ]);
    });
}

Now your icons can be referenced using a component, directive or helper:

<x-heroicon-o-bell/>

@svg('heroicon-o-bell')

{{ svg('heroicon-o-bell') }}

Don't forget to make blade-ui-kit/blade-icons a requirement of your package's composer.json.

Generating Icons

Blade Icons also offers an easy way to generate icons for your packages. By defining a config file with predefined source and destination paths, you can make updating your icons a breeze.

First, start off by creating a generation.php config file in the config directory of your icon package. Next, you can define an array per icon set that you want to generate. Below is a full version of this file with explanation for every option. Only the source and destination options are required.

<?php

use Symfony\Component\Finder\SplFileInfo;

return [
    [
        // Define a source directory for the sets like a node_modules/ or vendor/ directory...
        'source' => __DIR__.'/../node_modules/heroicons/outline',

        // Define a destination directory for your icons. The below is a good default...
        'destination' => __DIR__.'/../resources/svg',

        // Strip an optional prefix from each source icon name...
        'input-prefix' => 'o-',

        // Set an optional prefix to applied to each destination icon name...
        'output-prefix' => 'o-',

        // Strip an optional suffix from each source icon name...
        'input-suffix' => '-o',

        // Set an optional suffix to applied to each destination icon name...
        'output-suffix' => '-o',

        // Enable "safe" mode which will prevent deletion of old icons...
        'safe' => true,

        // Call an optional callback to manipulate the icon with the pathname of the icon,
        // the settings from above and the original icon file instance...
        'after' => static function (string $icon, array $config, SplFileInfo $file) {
            // ...
        },
    ],

    // More icon sets...
];

See an example config/generation.php file for the Heroicons package.

After setting up your config file you can use the icon generation as follow from the root of your icon package directory:

vendor/bin/blade-icons-generate

Changelog

Check out the CHANGELOG in this repository for all the recent changes.

Maintainers

Blade Icons is developed and maintained by Dries Vints.

License

Blade Icons is open-sourced software licensed under the MIT license.

Issues
  • Refactor to Blade Icons

    Refactor to Blade Icons

    I'm very happy to say that Adam was so kind to let me take over the library. I recently created my own Blade Icons package without realizing that Adam already created this wonderful package! After thinking it over I thought it would be perfect if we merged the two packages into one. So that's great news for everyone using this library as I'll be actively maintaining it and helping out with issues etc.

    There's some pointers on this so let's go through them. First of all, this PR is a complete rewrite of the package. If I'm going to maintain it and use it as a base for future packages/ideas I'd like to be familiar and comfortable with the library so a rewrite makes sense. You can check out the changes in this pr, the new README on its own branch as well as the upgrade guide.

    New Requirements

    There's some new minimum version requirements like PHP 7.2 and Laravel 7.14 (I need this version specifically for the Blade components). It doesn't makes sense to me to maintain anything for a PHP version that isn't getting active support anymore.

    New Features

    There's new stuff as well! The package now supports multiple icon sets which makes it very easy for third party packages to be created for it. When the refactor has been merged and released I'll release another "Heroicons" package alongside it which you can optionally pull in.

    Besides that you can now reference icons as Blade components. This is a very clean syntax and I personally much prefer this over a directive.

    Breaking Changes

    There's quite a few breaking changes unfortunately but making these changes now before a full 1.0 release is done will allow me to work with a syntax that I'm comfortable with. Please refer to the upgrade guide for the most notable ones.

    Package Renaming

    One last note I want to make is that this rewrite is part of a bigger plan that I have. Before this PR is merged I'll transfer the repo to a new organisation and rename its package name. I'll give more info as soon as we get to that.

    I need your help

    What I need most now is feedback and people testing the library, especially existing users. I'd much appreciate it! Try out this PR by installing it through Composer:

    composer require nothingworks/blade-svg:dev-next-version
    

    There's two things I'm currently considering before shipping the next 0.4.0 release:

    • ~Should we remove the sprite sheets functionality? It doesn't seems to be like something many people use and would clean up the internals a lot.~ (Sprite Sheets functionality was removed)
    • At the moment blade components icons are loaded with loading the file list on every request. It's probably best that we cache this somehow between requests.

    I'd much appreciate feedback so let me know what you think!

    opened by driesvints 35
  • Peformance concerns

    Peformance concerns

    Hi,

    I updated yesterday from the nothingworks/blade-svg package to the blade-ui-kit/blade-icons package and I'm seeing much higher CPU usage on my servers as well as a very large number of php slow log entries relating to the package on every single request.

    I am using the owenvoke/blade-fontawesome add on.

    It seems when there is a large number of icons, for instance the fontawesome package provides around 1,500 icons, it loads every single file in the filesystem on every request.

    Looking at https://github.com/blade-ui-kit/blade-icons/blob/main/src/Factory.php#L68-L81 it loads all the files in the filesystem (whether or not they're used) on every page request:

    But the previous package would only load them as they're used https://github.com/blade-ui-kit/blade-icons/blob/v0.3.4/src/SvgFactory.php#L105

    As an example of the slow log I'm seeing on every request:

    [07-Aug-2020 02:32:07]  [pool www] pid 8233
    script_filename = /srv/public/index.php
    [0x00007f5fa7616e40] hasChildren() /srv/vendor/symfony/finder/Iterator/ExcludeDirectoryFilterIterator.php:76
    [0x00007f5fa7616dd0] hasChildren() /srv/vendor/symfony/finder/Iterator/SortableIterator.php:91
    [0x00007f5fa7616d80] next() /srv/vendor/symfony/finder/Iterator/SortableIterator.php:91
    [0x00007f5fa7616d30] next() /srv/vendor/symfony/finder/Iterator/SortableIterator.php:91
    [0x00007f5fa7616cc0] iterator_to_array() /srv/vendor/symfony/finder/Iterator/SortableIterator.php:91
    [0x00007f5fa7616c40] getIterator() /srv/vendor/symfony/finder/Finder.php:772
    [0x00007f5fa7616b10] searchInDirectory() /srv/vendor/symfony/finder/Finder.php:614
    [0x00007f5fa7616a60] getIterator() /srv/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:460
    [0x00007f5fa76169f0] iterator_to_array() /srv/vendor/laravel/framework/src/Illuminate/Filesystem/Filesystem.php:460
    [0x00007f5fa7616970] allFiles() /srv/vendor/blade-ui-kit/blade-icons/src/Factory.php:71
    [0x00007f5fa76168b0] registerComponents() /srv/vendor/blade-ui-kit/blade-icons/src/BladeIconsServiceProvider.php:49
    [0x00007f5fa7616830] BladeUI\Icons\{closure}() /srv/vendor/laravel/framework/src/Illuminate/Container/Container.php:1141
    [0x00007f5fa7616790] fireCallbackArray() /srv/vendor/laravel/framework/src/Illuminate/Container/Container.php:1105
    [0x00007f5fa7616710] fireAfterResolvingCallbacks() /srv/vendor/laravel/framework/src/Illuminate/Container/Container.php:1090
    [0x00007f5fa7616690] fireResolvingCallbacks() /srv/vendor/laravel/framework/src/Illuminate/Container/Container.php:711
    [0x00007f5fa76165b0] resolve() /srv/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:796
    [0x00007f5fa7616510] resolve() /srv/vendor/laravel/framework/src/Illuminate/Container/Container.php:637
    [0x00007f5fa7616490] make() /srv/vendor/laravel/framework/src/Illuminate/Foundation/Application.php:781
    [0x00007f5fa7616400] make() /srv/vendor/laravel/framework/src/Illuminate/Container/Container.php:1284
    [0x00007f5fa7616390] offsetGet() unknown:0
    

    I've had to revert this package upgrade and move back to the deprecated old package which immediately solved the slowlog and cpu issues.

    enhancement 
    opened by RyanTheAllmighty 27
  • Add a general generator for icon package maintainers

    Add a general generator for icon package maintainers

    This PR adds the ability for blade-icons consumer libraries to easily create a generation script. The GenerateCommandBuilder accomplishes this by providing a fluent API to build a SingleCommandApplication that functions in 3 phases:

    1. Generate temp files for normalization from source files,
    2. Normalize the SVGs in the temp directory, (optional, only used when closure provided)
    3. Relocate the normalized SVGs to their destination path.

    Using a builder style pattern seems to be a better fit for both end-users and providing a good general purpose solution. At the current state I think it should be much more functional for most use cases compared to the first pass attempt.

    However, this is still a rather basic script and it could have some short comings for some Icon packs. Namely if the icon pack stores the "default" (or regular) set in the root directory and has variant sets in sub directories.

    For those cases it may make more sense to introduce a IconSetParameters DTO of sorts that would encapsulate the icon sets state and location. More input from other authors, or direct investigation into other icon packs may be needed.


    Here's what my boxicons package would use to make the generator work:

    GenerateCommandBuilder::create('blade-boxicons')
        ->fromNpmPackage('boxicons') // Optionally specify an `npm` package to load from
        ->fromSourceSvgDirectory('/svg') // Specify a directory, if an npm package isn't set, this can be anywhere
        ->withIconSets([
            IconSetConfig::create('regular')
                ->setInputFilePrefix('bx-'),
            IconSetConfig::create('logos')
                ->setInputFilePrefix('bxl-'),
            IconSetConfig::create('solid')
                ->setInputFilePrefix('bxs-'),
        ])
        ->withSvgNormalisation(function (string $tempFilepath, string $iconSet) {
            $doc = new DOMDocument();
            $doc->load($tempFilepath);
            /**
             * @var DOMElement $svgElement
             */
            $svgElement = $doc->getElementsByTagName('svg')[0];
            $svgElement->removeAttribute('width');
            $svgElement->removeAttribute('height');
            $svgElement->removeAttribute('viewBox');
            $svgElement->setAttribute('fill', 'currentColor');
            $svgElement->setAttribute('stroke', 'none');
            $svgElement->setAttribute('viewBox', '0 0 24 24');
            $doc->save($tempFilepath);
    
            $svgLine = trim(file($tempFilepath)[1]);
            file_put_contents($tempFilepath, $svgLine);
        })
        ->run();
    

    Example Implementations:

    My Boxicons Package: https://github.com/mallardduck/blade-boxicons/pull/1/files @owenvoke 's FontAwesome package: https://github.com/owenvoke/blade-fontawesome/pull/25 @driesvints Heroicons package: https://github.com/blade-ui-kit/blade-heroicons/pull/19

    opened by mallardduck 23
  • Automatic Sprite Sheet

    Automatic Sprite Sheet

    Is it possible to automatically create optimised sprite sheets?

    For example if you set 'automatic_spritesheet' => true when you use @icon('cog') it builds up a collection of the svgs used, then it prints out the spritesheet after the body, based on only the icons you've picked? So you can have individual .svg files in your asset folder still?

    Thanks :)

    enhancement 
    opened by OwenMelbz 15
  • Install Error

    Install Error

    Library version

    1.0.0

    Laravel version

    8.29

    PHP version

    7.4

    Description

    In Container.php line 1057:

    Unresolvable dependency resolving [Parameter #1 [ string $manifestPath ]] in class BladeUI\Icons\IconsManifest

    Steps to reproduce

    Install the package composer require blade-ui-kit/blade-icons

    bug 
    opened by xtreme2020 12
  • Installing the package breaks other package's directives

    Installing the package breaks other package's directives

    I haven't been able to figure out why, but as soon as I install this package and make any change to my view (or do php artisan view:clear as well), it no longer recognizes spatie/laravel-permission directives.

    My view just prints out the directives as text, like this:

    @hasanyrole('Administrador|Ventas') <x-menu.menu-item> @endhasanyrole

    I'm using Laravel 7.16

    question 
    opened by JuanDeLeon 11
  • Unable to locate a class or view for component XXX

    Unable to locate a class or view for component XXX

    Hi, just install the package as follow:

    - composer require blade-ui-kit/blade-icons
    - php artisan vendor:publish --tag=blade-icons
    

    Then in I blade put <x-icon-camera/> got this error:

     Unable to locate a class or view for component [icon-camera]. 
    

    What should I do next, cuz I read the docs and I do not fully understand it! :(

    bug 
    opened by jeanali 11
  • Blade helper renaming proposal

    Blade helper renaming proposal

    Hello. I was thinking about the package, when we're talking about SVG (scalable vector graphics), not every SVG is an "icon", it could be just a simple graphic or whatever. Perhaps shouldn't we consider renaming the helper @icon to @svg? Wouldn't it be better and more semantic flexible to the package? (I know we go the svg_icon as well, but my complaining is about the word "icon". What do you guys thinks? Cheers!

    opened by giovannipds 11
  • SVG with style tag + Vue

    SVG with style tag + Vue

    Hi,

    I am wondering if I am going about this the wrong way.

    I have SVGs with embedded styles (<style>...</style>) but I cannot use them if I am including them inside a Vue app as Vue will complain: Templates should only be responsible for mapping the state to the UI. Avoid placing tags with side-effects in your templates, such as