codeat3/blade-zondicons
Blade Zondicons brings the Zondicons icon set to Laravel Blade as simple, self-contained components. Drop icons into any view with a single tag, style them with classes, and skip copying SVG markup by hand.
Install and confirm. One command, no service provider registration, no config publishing — Laravel package auto-discovery picks it up:
composer require codeat3/blade-zondicons
The package is a thin wrapper over blade-ui-kit/blade-icons, which comes along as a dependency. Verify the tagged composer.json constraints in CI (PHP floor and illuminate/*) rather than trusting the one-line changelog — the 1.7.0 release is a compatibility-only bump for Laravel 13 (PR #239) with no new icons, config keys, or API changes.
Where to look first.
vendor/codeat3/blade-zondicons/resources/svg/ — the authoritative list of available icon names. Filenames map directly to component names.vendor/blade-ui-kit/blade-icons/ — the runtime that actually resolves and renders the SVG. Everything the package does is delegated here, so read this when behaviour surprises you.config/blade-icons.php (publishable via vendor:publish --tag=blade-icons-config) — the prefix and set registration live here if you ever need to rename or add sets.First use case. Drop a component into an existing Blade view — a sidebar nav item or a button — to prove the render path end-to-end:
<x-zondicon-home class="w-5 h-5 text-gray-500" />
Then smoke-test view compilation before wiring anything else up (php artisan view:clear && php artisan route:list, or just hit the page). This catches provider-registration and constraint problems for near-zero cost, which is the only realistic failure mode for a presentation-only package.
Wrap it on day one. Never scatter raw <x-zondicon-*> calls across views. One thin wrapper localizes sizing, colour, and accessibility conventions so a redesign is a one-file edit rather than a repo-wide find-and-replace:
{{-- resources/views/components/icon.blade.php --}}
@props(['name', 'size' => 'w-5 h-5'])
<x-dynamic-component
:component="'zondicon-' . $name"
{{ $attributes->merge(['class' => $size]) }}
aria-hidden="true"
/>
Usage becomes <x-icon name="heart" class="text-red-500" />. Swap w-5 h-5 for a size map (sm/md/lg) once design settles on a scale.
Sizing and colour. Because these are inline SVGs, Tailwind's w-*/h-* set the box and text-* sets currentColor. Zondicons are a solid, 20×20 set — if a glyph has a baked-in fill, pass fill="currentColor" explicitly so text-* utilities actually take effect. Treat the class list as the API contract; don't reach for style="" attributes.
Dynamic names. For CMS- or DB-driven icon names, use the Blade Icons helper instead of a raw tag:
@svg('zondicon-' . $icon, 'w-5 h-5 text-gray-400')
Always validate against an allowlist — an unknown name renders nothing rather than throwing, so a bad value fails silently in production.
Loop-heavy surfaces. In tables, nav lists, and paginated cards, wrap repeated icon markup in @once blocks only where the markup is genuinely identical; the component itself does not dedupe. Combine with the deploy-time cache for the biggest win.
Icon-only buttons. Accessibility is not automatic. Decorative icons get aria-hidden="true"; meaningful ones need a label:
<button type="button" class="p-2 rounded hover:bg-gray-100">
<x-icon name="trash" />
<span class="sr-only">Delete</span>
</button>
Deploy hygiene. Add to the deploy script, in order:
php artisan icons:clear && php artisan icons:cache
php artisan view:cache
icons:cache pre-registers every icon into a manifest — a real win on icon-dense pages. view:cache alone is not enough; stale view cache also hides newly added or renamed icons.
Testing. Icons are server-rendered, so you can assert them without a browser: $response->assertSee('<svg', false) on an icon-bearing page, or a targeted assertion in a Blade component test. Add a visual regression check on one or two icon-dense views — it's the only thing that catches an icon silently disappearing in a future release.
Typos fail silently. <x-zondicon-hart /> renders nothing — no exception, no console error, just a gap in the UI. This is the sharpest edge in the whole package. Mitigate with the wrapper component (which narrows the surface to one file) and the visual regression check above.
icons:cache makes everything frozen. Once the manifest is built, edited config, new prefixed components, and filesystem changes are invisible until you run icons:clear. If icons "stop working" after a config tweak, this is almost always the cause.
Naming is kebab-case and filename-derived. Names with digits, dashes, or unusual casing translate awkwardly into component syntax. Confirm the exact name from the vendor resources/svg directory rather than guessing; the docs and the description aren't reliable on the count either (the README says "220+", reference material cites ~290 — verify from the tagged package before quoting a number in a spec).
Component name collisions surface at view compile time. If you or another codeat3 package already ships a <x-zondicon-*> component, you'll get a compile failure, not a runtime warning — good news, because it's loud. Publish blade-icons config and change the prefix if you need to disambiguate.
Multiple codeat3 icon packages share one runtime. Heroicons, Eva Icons, and Zondicons all register against the same blade-icons manager. icons:cache covers all of them in one command, and a single wrapper convention should span all sets — decide the naming once rather than per package.
Inline SVG inflates payload. Every icon is inlined markup, so a 200-row table with three icons per row is a lot of repeated HTML. Not a blocker at typical scale, but if a page gets genuinely icon-dense, sprite-sheeting or <use> references become worth considering. icons:cache does not reduce output size — it only speeds up registration.
Zondicons is a frozen set. No new artwork is coming, upstream or via this package. Get that understood by design before adoption; the first "we need a brand icon" request is the moment the package stops being the answer, and the migration to a second set (or hand-authored SVGs) is trivial precisely because everything routes through one wrapper.
Attribute passthrough is your extension point. class, width, height, aria-*, data-*, x-bind, and Alpine directives all land on the root <svg> via $attributes. There is no other extension surface — no config keys, no slots, no render hooks. Design your wrapper with that in mind and you won't need one.
Pin and monitor. 48 stars, zero dependents, community-maintained. Scope a Dependabot/Renovate rule to this package so Laravel-major compatibility releases (like 1.7.0) surface automatically. Keep the exit path in the README: fork, or vendor the SVGs directly — both are viable because the package is presentation-only and namespaced.
How can I help you explore Laravel packages today?