codeat3/blade-devicons
Blade Devicons adds ready-made Laravel Blade components for rendering developer and technology icons in your views. Install via Composer, then drop simple, self-closing icon tags into any template—no extra config or asset setup required.
Install and render one icon
composer require codeat3/blade-devicons
That is the entire setup. The package is a thin distribution wrapper around blade-ui-kit/blade-icons: it vendors the Devicon SVG set and registers it under the devicon prefix, and Composer auto-discovery loads the service provider. No config file, no vendor:publish, no asset build step, no Vite change. If you already use Heroicons, Tabler, or Font Awesome through blade-icons, this registers alongside them — it does not replace the registry.
<x-devicon-laravel class="w-6 h-6" />
<x-devicon-docker class="w-8 h-8" />
Three checks before you write real templates
composer show codeat3/blade-devicons blade-ui-kit/blade-icons. The wrapper is a shell; the blade-icons major version is what actually governs whether this works with your Laravel/PHP combination. Note that number in your upgrade log, not the wrapper's version.vendor/codeat3/blade-devicons/resources/svg and confirm every slug you intend to use — including whether you need the -original, -plain, or -wordmark variant. This directory is your source of truth, full stop.x-devicon-* doesn't resolve, inspect the registered prefix before building anything on top of it.Best first use case
An integrations or "supported stacks" strip: 8–12 logos in a grid, each paired with a visible text label. It's the lowest design-risk surface, it validates the exact slugs you care about, and it's the natural replacement for hardcoded <img src="/images/logos/*.svg"> markup already in the app. Ship that, review the rendered markup, and only then expand into docs tables, comparison matrices, or changelog badges.
1. One wrapper component, always
The single highest-value pattern with a one-maintainer, zero-dependent package: never reference <x-devicon-*> directly in feature templates. Wrap it once and route everything through your wrapper.
{{-- resources/views/components/stack-logo.blade.php --}}
@props(['name', 'label' => null, 'size' => 'w-6 h-6'])
<span {{ $attributes->merge(['class' => 'inline-flex items-center gap-2']) }}>
<x-dynamic-component :component="'devicon-' . $name" class="{{ $size }}" aria-hidden="true" />
@if ($label)<span class="text-sm">{{ $label }}</span>@endif
</span>
Swapping to a hand-vendored set, a sprite sheet, or a different vendor later becomes a one-file change instead of a repo-wide grep. Do this on day one, not the day you need it.
2. Treat logo lists as data, not markup
Integration grids, comparison matrices, and docs requirement blocks are configuration. Keep the slug next to its display name and URL so adding a stack is a one-line change with zero template edits.
// config/stacks.php
return [
['slug' => 'laravel', 'name' => 'Laravel', 'url' => 'https://laravel.com'],
['slug' => 'postgresql', 'name' => 'PostgreSQL', 'url' => 'https://postgresql.org'],
['slug' => 'docker', 'name' => 'Docker', 'url' => 'https://docker.com'],
];
@foreach (config('stacks') as $stack)
<x-stack-logo :name="$stack['slug']" :label="$stack['name']" size="w-8 h-8" />
@endforeach
This is what makes pattern #1 pay off: the config array becomes the single surface you test, audit, and diff in code review.
3. Reach for the svg() helper only outside Blade
When you need icon markup from PHP — a view composer assembling nav, a Filament/Nova field, an export renderer — blade-icons exposes:
$html = svg('devicon-redis', 'w-5 h-5')->toHtml();
Use it sparingly. Inside templates the component syntax reviews better and merges attributes more predictably.
4. Size with classes; let CSS own the dimensions
Prefer class="w-5 h-5" over width/height attributes so Tailwind breakpoints and container queries can affect sizing. Reserve intrinsic numeric attributes for standalone exports or <img>-style embedding where you genuinely need SVG dimensions baked in.
5. Decide accessibility per usage, not per icon
aria-hidden="true", no title.<x-devicon-kubernetes class="w-5 h-5" role="img" aria-label="Kubernetes" />
When the icon sits inside a link or button, put the accessible name on the interactive element and keep the SVG aria-hidden — otherwise screen readers announce the logo and the link label separately.
6. Cache the icon manifest in your deploy pipeline
blade-icons can compile an icon manifest into bootstrap/cache. Add it after composer install:
php artisan icons:clear
php artisan icons:cache
Regenerate on every deploy and on any composer update that touches icon packages. A stale manifest is the classic "blank icons in production, fine locally" failure.
7. Know where it earns its keep
In rough priority order: integration/partner directories, docs requirement blocks and comparison tables, changelog area tags, and internal dashboards or runbooks where scan speed beats visual polish. These are all surfaces where the cost of an icon is currently an asset export and a naming debate, and where the logo is decorative rather than load-bearing.
Unknown slugs throw, they don't render blank. blade-icons raises SvgNotFound, so one bad slug inside a config-driven @foreach 500s the entire page. Guard it with a cheap test that resolves every configured slug:
it('resolves every configured stack icon', function () {
foreach (config('stacks') as $stack) {
expect(svg('devicon-' . $stack['slug'])->toHtml())->not->toBeEmpty();
}
});
Run it on every dependency bump — it's your early warning when an upstream rename silently orphans a slug.
Names are filenames with variants baked in. Expect -original, -plain, -wordmark, and combinations thereof. Which of those are registered is a property of this package's vendored directory, not of the Devicon project. Verify against resources/svg, never against the website.
color and fill frequently do nothing. Full-colour Devicon marks hardcode their brand fills, so theme colours, hover states, and dark-mode treatments won't propagate. If you need currentColor inheritance for a monochrome strip, switch to the -plain variant, which is usually a single-path mark. Decide this before a designer builds a palette around it.
Every instance inlines the full SVG. Forty logos means forty inline path sets, and a logo repeated in a loop is paid for on each iteration. Fine for a handful; measure before optimising a dense directory page. If you do optimise, @once-guarded sprite definitions are the low-effort path — but measure first, because the cost is markup churn, not payload.
Pin at ^1.9 or above. 1.9.0 is a compatibility-only release (Laravel 13 support, no API or markup change), so it's a safe in-place bump. Pinning below it quietly reintroduces a framework-upgrade blocker. Note that the release notes don't state the validated blade-icons major or PHP floor — prove the resolution in your own composer update rather than trusting the changelog.
Write down your exit plan on day one. One maintainer, one star, zero dependents. That's a bus-factor concern, not a code-quality one, and the mitigation is cheap because the payload is static SVGs. Choose either (a) keep all usage behind the wrapper from pattern #1, or (b) copy the handful of SVGs you actually use into resources/svg and register them as your own blade-icons set, dropping the dependency entirely. Either choice is fine; not making one is the mistake.
Attribute merging behaves the way you want — lean on it. {{ $attributes }} on your wrapper passes class, id, and Livewire/Alpine bindings through to the SVG, and class merges rather than replaces. That covers nearly all day-to-day customisation. When you need a per-icon special case, add a prop to your wrapper; don't start editing vendor tags inline.
Not portable to email or PDF. Inline SVG renders inconsistently in email clients and has limited support in dompdf-style generators, and a strict CSP will need the inline output audited. If any of those surfaces are in scope, treat this as web-view-only and provide a fallback (a PNG, or plain text).
Trademark isn't licence. The Devicon code is MIT; the logos belong to their owners. Internal dashboards and technical docs are low risk. A public "trusted by" or endorsement-flavoured marketing strip is a brand-permission question that needs a policy decision, not an engineering one — route it accordingly rather than assuming the MIT licence covers it.
Decide the namespace boundary once. Whether vendor logos share your existing <x-icon> vocabulary or live in a separate tier is cheap to settle now and expensive to retrofit across every template later. Pick one, write it down, and let the wrapper enforce it.
How can I help you explore Laravel packages today?