technikermathe/blade-lucide-icons
technikermathe/blade-lucide-icons brings Lucide’s clean SVG icon set to Laravel Blade as a simple reusable component. Install it, render icons in your views, and customize size, color, stroke, and CSS classes with intuitive attributes for consistent lightweight UI icons.
composer require pascalebeier/blade-lucide-icons
No service provider registration, no publish step, no config file required — the package registers an anonymous Blade component namespace (lucide) that maps every bundled SVG to a component name.
<x-lucide-search class="size-5" />
Where to look first:
vendor/pascalebeier/blade-lucide-icons/resources/views/ — one file per icon; the filename is the component name, so this directory is your authoritative icon list for the version you actually have installed.https://lucide.dev for browsing/visual search — but treat it as documentation of latest Lucide, not of your installed copy (see Gotchas).layouts/app.blade.php, nav partial) — that's where icon sizing/colour conventions get established and copied everywhere.First use case: replace hand-pasted inline SVGs in your nav and buttons with <x-lucide-{name} class="size-5" />, then grep for <svg in resources/views to find the remaining stragglers.
As of v3.195.0 the bundled set tracks Lucide 1.61.0.
Attribute passthrough is the whole API. Everything lands on the root <svg>, so Tailwind utilities and ARIA attributes work directly:
<x-lucide-trash-2 class="size-4 text-red-600" stroke-width="1.5" aria-hidden="true" />
Wrap it once so sizing isn't repeated 400 times:
{{-- resources/views/components/icon.blade.php --}}
@props(['name', 'size' => 'size-5'])
<x-dynamic-component :component="'lucide-'.$name" {{ $attributes->class($size) }} aria-hidden="true" />
Dynamic names (from config, DB, enum, permission checks) go through x-dynamic-component, not string interpolation inside a tag name.
Config-driven nav / menus:
['label' => 'Dashboard', 'icon' => 'layout-dashboard', 'route' => 'dashboard']
<x-icon :name="$item['icon']" />
Colour inherits — Lucide is stroke-based and uses currentColor, so text-gray-400 hover:text-gray-900 on the parent link themes the icon for free. There is no separate "fill" or "solid" variant.
Accessibility is on you. Decorative icons need aria-hidden="true"; standalone meaningful icons need role="img" + aria-label. Bake this into the wrapper above and you never think about it again.
Production caching. Rendering ~1,700 anonymous components means a filesystem lookup per icon per request. Run the package's cache command (php artisan blade-lucide-icons:cache — confirm the exact name in the README for your version) plus php artisan view:cache in your deploy pipeline, and rebuild both on every release. Given the release cadence (see Gotchas), "every release" can mean every few days — automate it rather than remembering it.
CI guard against renames — the single highest-value habit with this package:
grep -rhoP 'x-lucide-[a-z0-9-]+' resources/views | sort -u | \
sed 's/x-lucide-//' | while read i; do
test -f "vendor/pascalebeier/blade-lucide-icons/resources/views/$i.blade.php" || echo "MISSING: $i"
done
Custom/brand icons: don't jam them into the vendor directory. Register your own path with the same lucide prefix via Blade::anonymousComponentPath(resource_path('views/icons'), 'lucide') in a service provider so <x-lucide-*> resolves across both (verify precedence in your Laravel version), or keep a separate x-brand-* namespace.
feat — the third minor in the five days between v3.192.0 (Lucide 1.58.0) and v3.195.0 (Lucide 1.61.0). Composer will pull these happily under ^3.0, and three Lucide minor versions in a week is a lot of upstream rename/deprecation churn landing in your templates. A renamed icon means Unable to locate a class or view for component [lucide-foo], or, if you use x-dynamic-component with a stale string, a hard 500 on a page you didn't touch. Pin the exact version ("pascalebeier/blade-lucide-icons": "3.195.0") and upgrade deliberately with the CI check above, or accept that composer update can break templates.resources/views/ between tags if you want the exact rename list.composer update, run php artisan view:clear and re-run the icon cache command. New icons appearing blank/404 right after an upgrade is almost always a stale cache file in bootstrap/cache — which must be generated at deploy time and never committed.vendor:publish on a whim. Publishing copies the whole icon set into your repo, shadows future upstream fixes, and makes upgrades a merge conflict — especially painful when upstream syncs land weekly. Publish only to override a specific icon.size-*/h-* w-*.class is merged, not replaced by Laravel's ComponentAttributeBag, so wrapper defaults plus call-site classes combine — useful, but it means a call-site size-8 won't override a wrapper's size-5; it'll just be contradictory CSS. Prefer a single size prop.path for those outputs.x-lucide-* components expecting precedence — collisions resolve unpredictably and are miserable to debug.Blade::anonymousComponentPath() for layering your own icons under an existing prefix.How can I help you explore Laravel packages today?