andreiio/blade-iconoir
Blade Iconoir provides Laravel Blade components for the Iconoir SVG icon set, letting you render clean, customizable icons directly in your templates with simple, readable tags. Ideal for Laravel apps that need lightweight inline SVG icons without extra setup.
blade-iconoir turns the Iconoir SVG set into Laravel Blade components, so you render icons as tags instead of pasting SVG markup.
composer require andreiio/blade-iconoir
There is nothing to register — the service provider is auto-discovered and the components are available immediately. If you want to change the component prefix or set a global default class/attribute set:
php artisan vendor:publish --tag=blade-iconoir-config
First use case: drop an icon into an existing layout or nav item.
<x-iconoir-home class="w-5 h-5" />
<a href="/settings"><x-iconoir-settings class="w-4 h-4" /> Settings</a>
Find the component name by taking the icon's name from iconoir.com and kebab-casing it (arrow-right → <x-iconoir-arrow-right />). Icons inherit currentColor on the stroke, so a wrapping text-gray-500 colors the icon for free.
Current release (4.7.1) is a maintenance bump: CI action versions plus a regeneration against Iconoir v7.11.1. No API or component-signature changes, so it is a drop-in upgrade from 4.7.0 — but the underlying icon set moved, so re-check any icon whose artwork you depend on.
Direct components. Use <x-iconoir-*> inline wherever you need an icon. Attributes you put on the tag (class, stroke-width, width, height, aria-*, x-on:click, wire:click) land on the root <svg>, so Alpine and Livewire bindings work without a wrapper.
A thin app-level wrapper. If you expect to swap icon packs later, or want consistent sizing and accessibility defaults, wrap once:
{{-- resources/views/components/icon.blade.php --}}
@props(['name', 'size' => 'w-5 h-5'])
<x-dynamic-component :component="'iconoir-'.$name" {{ $attributes->class($size) }} aria-hidden="true" />
Then <x-icon :name="$item->icon" /> everywhere. This is also the seam where you'd add a title for meaningful (non-decorative) icons.
Dynamic names from data. 'iconoir-'.$name with <x-dynamic-component> is the standard trick for menus, notification types, or CMS-driven settings. Sanitize/whitelist the name if it comes from user input — a bad component name throws a ComponentNotFoundException at render time.
Consistent sizing. Define your scale once (w-4 h-4, w-5 h-5, w-6 h-6) and stick to it; passing both width/height and Tailwind classes conflicts. Let the class win and leave the SVG's intrinsic size alone.
Pruning the set. The package ships ~1,500 icons as compiled Blade views. If you only use a couple dozen, publish the components and delete the rest to cut vendor size and OPcache pressure — or keep the vendor set and accept it (it costs nothing at runtime unless rendered).
Mail and Markdown. Blade components work in Mailables and Mail::markdown() views, but CSS classes won't survive most email clients. For mail, prefer width/height/stroke attributes inline over Tailwind classes.
Testing. Assert with assertSee/assertSeeHtml on the rendered SVG, or assert the component renders: $this->blade('<x-iconoir-home />')->assertSee('<svg');. Snapshot-style assertions on exact SVG paths will break on every icon-set bump — assert presence, not geometry.
php artisan view:clear first — Blade caches the old compiled views).view:clear is the first debugging step for "component not found" or stale artwork after composer update. Also check config:clear if you edited the published config, and composer dump-autoload if you published components into resources/views.iconoir prefix and also have <x-iconoir-something /> in resources/views/components, resolution order decides the winner. Your own component directory generally takes precedence; rename yours if behavior is ambiguous.fill="currentColor" on the tag produces blobs. For emphasis, use stroke-width="2" or a background circle instead.stroke-width is per-icon, not global unless you bake it into the published config or your wrapper. Inconsistent 1.5 vs 2 across the app is a common visual bug.class. A global default class in the config and a class on the tag don't always merge the way you expect — verify which wins in your version rather than assuming $attributes->class() semantics.aria-hidden="true"; meaningful icons need a role="img" plus an accessible name (visually hidden text or a wrapping element with a title). The bare component does not add either.Cache::remember, or a small helper) instead of re-rendering per row.x-icon component. There's no plugin API — the wrapper approach is the intended customization path.How can I help you explore Laravel packages today?