codeat3/blade-akar-icons
Blade Akar Icons gives Laravel developers a simple Blade component API for rendering the Akar Icons SVG set. Install the package, then drop icon components into your views with configurable size, color, and attributes—clean inline SVGs with no manual markup or asset files.
Install
composer require codeat3/blade-akar-icons
That is the entire setup. The service provider is registered through Laravel package auto-discovery — no config/app.php edit, no vendor:publish, no asset build step, no JS. It pulls in blade-ui-kit/blade-icons as its renderer; that transitive package, not this one, is the real version gate on framework upgrades.
Verify discovery before writing a line of view code
php artisan about # confirm the provider is booted
composer dump-autoload # if you just added it to a long-running container
php artisan view:clear # stale compiled views hide newly registered components
Where to look first
https://akaricons.com — browse the actual glyph set. The wrapper is irrelevant if Akar doesn't have the glyph you need; validate coverage here, not in code.vendor/codeat3/blade-akar-icons/ — grep for names to confirm the exact kebab-case identifier. Guessing names is the #1 source of wasted time with icon packages.ls vendor/codeat3/blade-akar-icons/
grep -r "arrow" vendor/codeat3/blade-akar-icons/ | head -20
First use case — an icon in a button. Every Akar icon is <x-akar-{name} />:
<button type="submit" class="inline-flex items-center gap-2 rounded bg-blue-600 px-4 py-2 text-white">
<x-akar-check class="w-5 h-5" />
Save changes
</button>
The component emits an inline <svg> with a viewBox, fill="none", and stroke="currentColor". Because it uses currentColor, it inherits the button's text colour for free. Because it has a viewBox, Tailwind's w-5 h-5 scales it correctly even if the source SVG ships width="24" height="24" (CSS beats presentational attributes).
If you instead want the icons somewhere else — resources/views/components/ui/, a partials partial, a Livewire view — nothing changes. Components are globally available once the provider boots.
This is the most common day-to-day case and the one most often done wrong:
<button type="button" class="p-2 rounded hover:bg-gray-100">
<x-akar-x class="w-5 h-5" aria-hidden="true" />
<span class="sr-only">Close dialog</span>
</button>
Rule of thumb: decorative icons get aria-hidden="true", meaningful ones get a label. If the icon is the only content, either add sr-only text (preferred — it survives CSS failures and screen-reader quirks) or put role="img" aria-label="Close" on the SVG itself. Never leave a bare icon button unlabelled.
Do not let w-4 h-4 vs w-5 h-5 vs w-6 h-6 be a per-file decision. Wrap it:
{{-- resources/views/components/ui/icon.blade.php --}}
@props(['name', 'size' => 'md'])
@php
$sizes = ['xs' => 'w-3 h-3', 'sm' => 'w-4 h-4', 'md' => 'w-5 h-5', 'lg' => 'w-6 h-6'];
@endphp
<x-dynamic-component
:component="'akar-'.$name"
{{ $attributes->merge(['class' => ($sizes[$size] ?? $sizes['md']).' shrink-0']) }}
/>
Usage becomes stable and refactorable:
<x-ui.icon name="trash" size="sm" class="text-red-600" />
Two things worth noting: shrink-0 prevents flex children from squashing the icon, and $attributes->merge() is what makes the text-red-600 above survive instead of being silently dropped.
If icons appear in more than one place per concept, map the concept once:
// config/ui-icons.php
return [
'dashboard' => 'home',
'settings' => 'gear',
'logout' => 'arrow-right-from-bracket',
'edit' => 'pencil',
'delete' => 'trash',
];
<x-ui.icon :name="config('ui-icons.delete')" size="sm" />
When Akar renames or you swap icon sets, you edit one file. This is the cheapest insurance you get against the single-maintainer/upstream-drift risk.
Status badges driven by an enum or DB column:
@php
$statusIcons = ['paid' => 'check', 'pending' => 'clock', 'failed' => 'x'];
@endphp
<span class="inline-flex items-center gap-1 text-sm">
<x-dynamic-component :component="'akar-'.($statusIcons[$status] ?? 'alert')" class="w-4 h-4" />
{{ ucfirst($status) }}
</span>
Guard the lookup. A missing key throws Unable to locate a class or view for component [akar-] at render time, in production, on the one page you didn't click through.
Nav is the package's sweet spot — swap emoji or PNGs for consistent inline glyphs:
<nav class="space-y-1">
@foreach (config('ui-icons') as $label => $icon)
<a href="{{ route($label) }}"
class="flex items-center gap-3 rounded px-3 py-2 hover:bg-gray-100
{{ request()->routeIs($label) ? 'text-blue-600 font-medium' : 'text-gray-700' }}">
<x-akar-dynamic :name="$icon" class="w-5 h-5" />
{{ ucfirst($label) }}
</a>
@endforeach
</nav>
Empty states and form affordances work the same way — an icon in an absolute-positioned span inside a relative input wrapper, a large muted glyph centred above "No results yet".
In Livewire, icons are just Blade output — they re-render with the component with no special handling, and stay in sync with reactive state because they're server-rendered. In Inertia, use them in your root Blade layout and in any server-rendered shell; for React/Vue pages, prefer the JS icon equivalent so you don't end up with two icon conventions (see Gotchas).
Inline SVG is genuinely useful for internal transactional mail, but do not assume it works. Gmail's mobile and some webmail clients, and Outlook desktop for Windows, strip or fail to render inline SVG. If a template must work in every client, keep the SVG behind a client check or use a PNG fallback for the same slot. Don't ship an icon-only call-to-action to email without a text label next to it.
The Unable to locate a class or view for component [akar-foo] error has exactly three causes. (1) The icon name doesn't exist in Akar — check vendor/codeat3/blade-akar-icons/. (2) composer dump-autoload wasn't run after install. (3) You have "extra": { "laravel": { "dont-discover": [...] } } in composer.json, or a manual provider list, in which case register Codeat3\BladeAkarIcons\BladeAkarIconsServiceProvider yourself. Rule these out in that order; do not start editing views.
Colour comes from currentColor + a text class, not fill. The SVGs are stroke-based with stroke="currentColor". So <x-akar-heart class="text-red-500" /> works; <x-akar-heart fill="red" /> will either do nothing visible or produce a filled blob depending on the glyph. Set colour on the element or an ancestor with a text-* class.
Sizing with class beats width/height attributes. Both work, but pick one style and stick to it. Mixing <x-akar-check width="20" height="20" /> with Tailwind w-5 h-5 in the same codebase produces mystery 24px icons that override nothing.
Class merging is per-component, so test it once. Laravel's attribute bag merges class and style specially, but how a given version of the underlying SVG component renders {{ $attributes }} determines whether your passed class replaces or appends to the base class. Open devtools on one icon after install and confirm. If the class isn't landing, use $attributes->merge() in a wrapper rather than fighting the component.
Names are not always what you'd guess. x not close, pencil not edit, gear maybe not settings. Always cross-check against the vendor directory or akaricons.com rather than assuming lucide/heroicons naming. Ten seconds of grep beats a ViewException in staging.
Nothing is tree-shaken — inline SVG is markup on every page. That's fine for a nav bar and genuinely not fine for a 500-row table where each row renders three icons. If you hit that, either reduce to one icon per row, or bite the bullet and hand-roll an SVG <symbol> sprite with <use> — which reintroduces exactly the pipeline this package removes, so only do it if profiling says so. Don't optimise preemptively.
Pin the version and gate the Laravel 13 upgrade on the right package. 1.26.0 is a compatibility-only release whose sole documented change is Laravel 13 support (PR #47). Treat that as declared, not proven until your CI renders a page. More importantly, the actual constraint is blade-ui-kit/blade-icons — the maintainer here doesn't control it. Verify both support matrices in the same pass; otherwise you'll pin this dependency, upgrade the framework, and hit the wall one package deeper. On Laravel 10–12, ^1.25 || ^1.26 resolves fine and is purely additive.
Don't let akar- collide with your own components. The prefix is namespaced enough that coexistence with hand-rolled SVG partials is safe — this package only adds component names. Migrate view-by-view attached to feature tickets rather than as a sweep; two conventions can live side by side indefinitely without either breaking.
Add one smoke test so upgrade day isn't a surprise. A route or view test that renders two or three real icons and asserts <svg appears (with assertSee(..., false) so it isn't HTML-escaped) catches autoload, discovery, and component-rename regressions in under a second:
public function test_icons_render(): void
{
$this->get('/dashboard')
->assertOk()
->assertSee('<svg', false)
->assertDontSee('akar-', false); // unrendered component names leaking as text
}
Check for a second source of truth before adopting broadly. If your frontend component library (React/Vue design system, sprite pipeline) already ships icons, adding this creates two conventions and two upgrade paths. That's a governance cost, not a bug — decide it deliberately, and keep it out of brand-critical surfaces either way.
Bus factor is real but bounded. One maintainer, a large family of sibling blade-* packages, seven stars. Acceptable for chrome, unacceptable for anything load-bearing. The exit is genuinely cheap — the icons are static SVGs, so if the package is abandoned you vendor the dozen you actually use and swap the tags in an afternoon. Keep it as a convenience dependency and you keep that exit.
How can I help you explore Laravel packages today?