Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Blade Icons Laravel Package

blade-ui-kit/blade-icons

Blade Icons lets you drop SVG icons into Laravel Blade views with a simple component or directive, like or @svg('camera', 'w-6 h-6'). It's a lightweight base package with many third-party icon set packages available.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the base package, then publish and uncomment the configuration — this is the single most common reason a fresh install "does nothing":

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

In config/blade-icons.php, uncomment the default set and point it at a directory that exists:

'sets' => [
    'default' => [
        'path' => 'resources/svg',   // relative to base_path(), resource_path() also works
    ],
],

Drop any *.svg file (a single root <svg> element, no XML declaration) into resources/svg, and you immediately get two APIs for free:

<x-icon-camera class="w-6 h-6" />      {{-- component, prefix "icon" for the default set --}}
@svg('camera', 'w-6 h-6')              {{-- directive --}}
@svg('camera', 'w-6 h-6', ['fill' => 'none', 'data-testid' => 'camera'])

Where to look first: config/blade-icons.php (set definitions, prefixes, defaults, cache), resources/svg (your own set), and the icon search at https://blade-ui-kit.com/blade-icons#search before you hand-draw anything. Prefer an existing icon package (Blade Heroicons, Blade Lucide, Blade Font Awesome, etc.) over committing hundreds of SVGs — they register their own set and prefix via config.

First real use case: take the inline <svg> blobs already scattered through your layouts/ and button partials, extract them to resources/svg, and replace each call site with <x-icon-…>. You get one source of truth per glyph, class passthrough for Tailwind sizing/colour, and greppable usage.

Implementation Patterns

Component vs. directive vs. helper. Use <x-icon-camera /> for static, known icons in Blade templates — it's discoverable and IDE-friendly. Use @svg($name) when the icon name is data-driven (a menu item row with an icon column, a status badge mapping). When you need the markup outside a Blade rendering context (a JSON payload, a notification array, a PDF builder), use the svg() helper, which returns a BladeUI\Icons\Svg object implementing Htmlable:

$icon = svg('camera', 'w-6 h-6');
return ['html' => $icon->toHtml()];

Multi-set config with prefixes. The default set uses the icon prefix; other sets default to their set name unless you set prefix. Give each library a stable, short prefix and its own directory:

'sets' => [
    'default' => ['path' => 'resources/svg'],
    'heroicon' => [
        'path' => 'vendor/blade-ui-kit/blade-heroicons/resources/svg',
        'prefix' => 'heroicon',
        'class' => 'w-5 h-5',
        'attributes' => ['fill' => 'none', 'stroke' => 'currentColor'],
    ],
],

Set-level class and attributes act as defaults for every icon in that set — the natural place to put aria-hidden="true", fill="none", or a baseline size so templates stay terse.

Wrap it in your own component. Don't call <x-icon-*> directly from every view; build a design-system wrapper so sizing, accessibility, and variant mapping live in one place:

{{-- resources/views/components/ui/icon.blade.php --}}
@props(['name', 'size' => 'md'])
@php
    $sizes = ['sm' => 'w-4 h-4', 'md' => 'w-5 h-5', 'lg' => 'w-6 h-6'];
    $set = str_contains($name, '.') ? $name : "default.$name";
@endphp

<x-dynamic-component
    :component="'icon-' . str_replace('.', '-', $name)"
    {{ $attributes->merge(['class' => $sizes[$size]])->merge(['aria-hidden' => 'true']) }}
/>

Or back it with an enum/registry class (Icon::Camera->value) so a rename in the icon set is a one-line change rather than a global search-and-replace.

Runtime names. Blade component names can't be interpolated directly — use <x-dynamic-component :component="'icon-'.$icon" />, @svg($icon), or the wrapper above. Validate $icon against an allow-list; never pass raw request input into @svg (it resolves names to filesystem paths and outputs raw markup).

Deploy and cache. The package builds an icon manifest; in production cache it as part of your deploy script so you don't hit the filesystem for every render:

php artisan icons:cache

Run it after composer install so vendor-provided icon set paths exist, and pair it with icons:clear locally when adding icons. Add php artisan icons:clear to any "new icon added" dev workflow, or simply disable the cache in local.

Non-HTML output. Email templates strip <style> and often class-based styling, so set explicit fill/stroke/width/height attributes on the icon rather than relying on Tailwind classes. The same applies to DomPDF/Snappy renders: pass concrete attributes via the third @svg argument.

Testing. Assert rendered output with assertSee('camera', false) on the view, or assert the directive/component throws BladeUI\Icons\Exceptions\SvgNotFound for a bad name. A simple test that iterates your icon enum and renders each one catches renamed/removed files before a user does.

Gotchas and Tips

  • The uncommented default set is the #1 failure mode. Installed, published, no icons found → check config/blade-icons.php first, then verify the directory actually exists. A set registered with a non-existent path fails silently until render time.
  • Stale cache beats correct code. New SVG doesn't appear, or a deleted icon still renders: run icons:clear (and icons:cache in prod). Also remember php artisan config:cache after editing set definitions.
  • SvgNotFound in production surfaces as a 500 inside a loop (e.g. a table row with a missing icon in the DB). Wrap user-facing dynamic lookups in a try/catch and fall back to a known-good icon, or configure a fallback set so a missing icon resolves elsewhere instead of throwing.
  • SVG hygiene matters. One root <svg>, no <?xml ?> prolog, no embedded <script> or event handlers, and keep viewBox. Icons authored at inconsistent viewBox sizes will look misaligned even with identical classes.
  • Attribute merging is where surprises live. Component-passed attributes land on the root <svg> and set-level defaults are applied underneath; class precedence and boolean attributes (fill="none" vs a set default) are worth a two-minute check in vendor/ when something refuses to override. If you fight it repeatedly, move defaults out of the set config and into your own wrapper.
  • Colour comes from currentColor. If an icon won't respond to text-red-500, the source SVG has a hard-coded fill="#000" or stroke="#000". Normalise to currentColor when importing a set.
  • Performance in loops. Each distinct icon render parses markup; 200 table rows of inline SVGs bloat HTML noticeably. Cache the manifest, memoise repeated icon names, and for icon-dense dashboards consider an SVG sprite with <use> instead of inline duplication.
  • Accessibility is on you. Decorative icons need aria-hidden="true" (and focusable="false" for legacy Edge); meaningful icons need role="img" plus an aria-label or an embedded <title>. Bake this into the wrapper component so it's never forgotten.
  • Filenames are case- and separator-sensitive (ArrowUp.svg ≠ arrow-up.svg on Linux CI, fine on macOS). Standardise on lowercase kebab-case. Nested subdirectories exist in the wild but directive and component resolution treat them differently across versions — verify before reorganising an icon set into folders.
  • Vendor paths move on upgrade. Pointing a set at vendor/…/resources/svg breaks if a package restructures or you use a custom vendor-dir (COMPOSER_VENDOR_DIR). Prefer first-party icon packages that publish correct config, and re-run icons:cache after every composer update.
  • Extension points worth knowing: swap or extend BladeUI\Icons\Factory (bound as a singleton) to add set resolution logic programmatically, use Factory::svg() to fetch an Svg instance server-side, and register your own Blade directive/component wrapper if you want per-project conventions like @ui-icon('camera', 'lg'). Registering sets from a service provider is also a clean way to make a private in-house icon library available without touching config/blade-icons.php.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo
bernskioldmedia/laravel-harvest
bernskiold/laravel-data-scrubber
bernskiold/laravel-currency-converter
bernskiold/laravel-campaign-monitor
bernskioldmedia/laravel-autotranslate
siberfx/telegram-bot
roy-sandip/laravel-view-extended
gregsphotography/site-builder-core
roy-sandip/laravel-view
anodyne/blade-fluentui-icons
webx-ui/module-catalog-collections