codeat3/blade-simple-icons
Laravel Blade components for rendering Simple Icons SVGs with clean syntax. Use brand icons by name in any Blade view, customize size and color, and avoid extra JavaScript or asset pipelines.
Install and verify what you actually got.
composer require codeat3/blade-simple-icons
There is no service provider to register, no migration, no config publish step, no JS build. Auto-discovery handles registration. The install is genuinely one line — the meaningful work is confirming the component prefix.
Find the prefix in the vendor tree, not the README. The package has documented the prefix as both simpleicon and si in different places. The source of truth is the installed components directory:
ls vendor/codeat3/blade-simple-icons/resources/views/components | head -50
If your components land as laravel.blade.php under a simpleicon/ folder, your tag is <x-simpleicon-laravel />. If they land under si/, your tag is <x-si-laravel />. If a published config exists (config/blade-simple-icons.php), check for a prefix key — and check it against other Blade icon packages already installed, because a prefix collision silently makes one package’s icons resolve to the other’s.
First use case — a static social/tech row. Drop an icon anywhere a Blade component is legal:
<a href="https://github.com/yourorg" aria-label="GitHub">
<x-simpleicon-github class="w-6 h-6 text-gray-700 hover:text-black transition" />
</a>
The rendered output is an inline <svg> that inherits currentColor. Size and colour come entirely from your existing Tailwind/CSS utilities — no width/height props, no icon-specific sizing API. That is the whole integration surface.
Find your icon slug before writing the tag. Slugs are normalised, not brand names: .NET → dotnet, C++ → cplusplus, 1Password → 1password, Amazon Web Services → amazonwebservices. Browse simpleicons.org or ls the vendor components directory. Copy-pasting a tag that doesn’t exist throws a ComponentNotFound-style exception, so verify the slug first rather than debugging a 500 later.
Recommended before your second call site: build one brand-icon wrapper component (see Implementation Patterns). Static pages are fine with raw components; anything database- or CMS-driven needs the wrapper.
Static markup → raw components. Everything else → your own wrapper.
For a handful of hard-coded icons in a footer, social row, or payment strip, use the raw component directly. It’s the lowest-friction path and reads cleanly in review.
For anything driven by data — partner directories, integration grids, "works with" strips, tech-stack badges from a brands table — seal the package behind a single seam:
{{-- resources/views/components/brand-icon.blade.php --}}
@props(['name', 'label' => null])
@php
$slug = config("brand-slugs.{$name}", null);
$exists = $slug && \Illuminate\Support\Facades\Blade::getClassComponentAliases()["simpleicon-{$slug}"] ?? null;
@endphp
@if ($slug && view()->exists("components.simpleicon.{$slug}"))
<x-dynamic-component
:component="'simpleicon-'.$slug"
{{ $attributes->merge(['class' => 'inline-block']) }}
@if($label) role="img" aria-label="{{ $label }}" @else aria-hidden="true" @endif
/>
@else
{{-- Fallback: generic glyph or text label --}}
<span {{ $attributes->merge(['class' => 'inline-block']) }} aria-hidden="true">•</span>
@endif
A couple of practical notes on the wrapper:
view()->exists() for the guard, not exception handling. Catching a thrown exception per icon is expensive and can mask real errors in a 50-icon grid.config/brand-slugs.php). It is reviewable in a PR, greppable when a brand rebrands, and it removes the temptation to scatter raw tags across views.{{ $attributes->merge(...) }} lets call sites pass class, wire:loading, x-show, etc., and keeps the wrapper interchangeable with the raw component if you ever swap the underlying library.Dynamic resolution with x-dynamic-component. Once you have a slug, this is the escape hatch that lets you render by variable instead of literal tag name. It is the right primitive for loops, but wrap it — a typo’d slug throws at render time and the exception message does not tell you which icon failed.
Accessibility presets. Decide once, encode in the wrapper:
<a> or <button>: aria-hidden="true", no title.role="img" plus a <title> child or aria-label.aria-hidden and aria-label — that is a screen-reader contradiction.Large grids: render once, cache the HTML. Every <x-simpleicon-* /> is a view resolution. A 60-logo "integrations" page resolving 60 components per request is measurable. Render the grid to a string and cache it:
@cache('brand-grid-v1', 3600)
<div class="grid grid-cols-6 gap-4">
@foreach ($brands as $brand)
<x-brand-icon :name="$brand->slug" />
@endforeach
</div>
@endcache
Bump the cache key when you upgrade the package — icon SVGs change, cached HTML does not.
Blade mailables and notifications. Inline SVG survives email rendering far better than <img src="cdn..."> for most clients, and it removes a third-party request from a privacy-sensitive surface. This is one of the package’s underrated wins — reuse the same wrapper.
Admin surfaces (Filament / Nova). Use the wrapper inside HTML-capable fields (Filament\Forms\Components\Placeholder, table TextColumn::html()). The inline SVG renders fine in those contexts; you do not need to serialise icons into JSON or push them to the frontend.
Livewire. Because the component is server-rendered and stateless, it just works inside Livewire trees. No wire:ignore needed. If you have an x-show toggle on the icon itself, put it on the wrapper, not the inner <svg>, or you may get duplicate-hydration warnings.
Slugs are part of your public surface. This is the single most important thing to internalise. Icon names change when a brand rebrands or issues a trademark takedown, and — critically — those renames ship in patch releases. A composer update that looks routine (8.11.0 → 8.12.0, an automated upstream re-sync) can remove a component you depend on. Mitigations:
grep -r 'simpleicon-' across views before upgrading.Version semantics are decoupled from upstream. Wrapper 8.12.0 corresponds to simple-icons 16.12.0 upstream, but the wrapper’s major number does not track upstream’s. "We’re on ^8" tells you nothing about which brands you have. The only reliable manifest is the component directory in the installed vendor tree:
ls vendor/codeat3/blade-simple-icons/resources/views/components \
| sed 's/\.blade\.php//' | sort > brand-icons-inventory.txt
Diff this file on upgrade — that is your actual changelog.
view:clear after every composer update. The compiled views directory caches component resolution. Without clearing it you can get stale errors where a component exists on disk but Blade still can’t find it — or the reverse, where a removed icon still renders from cache in dev and only 500s in prod. Run it in your deploy script:
php artisan view:clear && php artisan view:cache
Never deploy with --no-dev. The components live in vendor/ and are require-type, not require-dev, but a build pipeline that prunes or excludes vendor views (some Docker multistage setups do) will silently break every icon. Confirm after build:
php artisan tinker --execute="dump(view()->exists('components.simpleicon.github'));"
Monochrome only — do not expect brand fidelity. Simple Icons is a normalised, single-colour 24×24 set. Logos with multi-colour identity (Google, Microsoft, Slack) render as flat silhouettes. If the design requires brand-faithful treatment, this package cannot deliver it; you need vendored brand SVGs from each vendor’s guidelines. Set this expectation with design before the first pull request, not after.
Trademark is a separate question from the MIT license. The package code is MIT; the logos are governed by each brand’s own guidelines. Using a logo in a customer-facing "works with" grid is generally fine; implying endorsement, recolouring in ways a brand forbids, or using a mark as your own product identity is where legal exposure lives. Get a one-time sign-off on the policy rather than debating per ticket. Practically: this is also why icons disappear from upstream — removals are frequently legal-driven, not technical, which means "why did this icon vanish?" conversations should start with a trademark check, not a bug hunt.
Prefix collision with other Blade icon packages. If you already have blade-heroicons, blade-feather-icons, or similar, check the effective prefix before assuming <x-simpleicon-*> works. Two packages with the same prefix produce a "first one wins" resolution with no warning. The installed component directory is the arbiter, not the README.
CSP: inline SVG is fine, inline styles are not always. The icons render as plain <svg>, which is CSP-safe. But if you or the wrapper add style="" attributes (common when passing arbitrary size props), a strict style-src policy will break them. Prefer Tailwind classes everywhere. If you are tightening CSP as a result of adopting this package — which is a legitimate motivator — remember to also audit the rest of your markup for style attributes before flipping the policy.
Page weight on large grids. Inline SVG ships bytes with every response, whereas a shared sprite sheet or icon font would be cached by the browser. For grids above roughly 50 icons, either cache the rendered HTML or split into pages / lazy-load sections. This is a deploy-output concern, not a vendor-size concern — the package’s footprint in vendor/ is irrelevant at runtime.
Supply chain. Small project, single maintainer plus an automated sync bot, near-zero dependents. That is a real but manageable risk because the artifact is generated from a public upstream dataset — the exit path is cheap. If the package is abandoned, you can regenerate components from simple-icons yourself in an afternoon, or fork. Pin the version in composer.json (exact or tight-caret) and keep the brand-icon wrapper so the swap is one file.
Debugging a "component not found" error. Order of checks:
dotnet, not .net — check vendor dir or simpleicons.org.)simpleicon vs si.)view:clear been run since the last composer change?vendor/codeat3/.../views/ present in the deployed artifact?git log the inventory file.The exception itself usually won’t name the icon, so a fast answer to "which icon?" comes from grepping the template, not reading the stack trace.
Extending / publishing. If you need custom icons alongside the package ones, publish the components (or add a parallel resources/views/components/ directory with the same prefix) rather than forking. Keeping the package vendored-pinned and layering custom components on top preserves the cheap-upgrade path.
How can I help you explore Laravel packages today?