codeat3/blade-file-icons
A Laravel Blade package for rendering file-type icons directly in your templates. Drop-in components make it easy to show icons for documents, images, archives, code files, and more, with simple customization for size and style.
Install with Composer; the service provider auto-registers, so nothing else is required:
composer require codeat3/blade-file-icons
If you have config or compiled views cached from an earlier deploy, clear them once:
php artisan view:clear && php artisan optimize:clear
Where to look first. There is no published config, no migrations, and no env vars. The authoritative source of truth for what you can actually use is the icon set shipped in the package — browse vendor/codeat3/blade-file-icons/resources/svg/ to enumerate the available names. Any file in that directory maps to a Blade component by its filename, prefixed with fileicon:
resources/svg/php.svg → <x-fileicon-php />
resources/svg/file-pdf.svg → <x-fileicon-file-pdf />
Everything else behaves exactly like blade-ui-kit/blade-icons, which the package is built on.
First use case. Drop an icon next to a filename in an upload or attachment list:
<x-fileicon-file-pdf class="w-5 h-5 text-red-600" />
<span>{{ $attachment->name }}</span>
That is the full API surface. Pick the component name, pass class, and the inline SVG inherits your Tailwind sizing and color utilities because the markup uses currentColor and no hardcoded dimensions.
Centralize the extension → icon mapping behind one wrapper. This is the single most important pattern. Do not scatter literal <x-fileicon-*> tags across views, because the mapping becomes a convention nobody owns and every new file type means edits in five templates.
{{-- resources/views/components/file-type-icon.blade.php --}}
@props(['extension' => null, 'class' => '{w-5 h-5}'])
@php
$map = [
'pdf' => 'file-pdf',
'doc' => 'file-word',
'docx' => 'file-word',
'xls' => 'file-excel',
'xlsx' => 'file-excel',
'csv' => 'file-excel',
'ppt' => 'file-powerpoint',
'pptx' => 'file-powerpoint',
'zip' => 'file-zip',
'rar' => 'file-zip',
'png' => 'file-image',
'jpg' => 'file-image',
'jpeg' => 'file-image',
'svg' => 'file-image',
'mp4' => 'file-video',
'mp3' => 'file-audio',
'php' => 'file-php',
'js' => 'file-js',
'json' => 'file-json',
];
$key = strtolower(ltrim((string) $extension, '.'));
$icon = $map[$key] ?? 'file';
@endphp
<x-dynamic-component
:component="'fileicon-'.$icon"
:class="$class"
aria-hidden="true"
/>
Usage becomes uniform everywhere:
<x-file-type-icon :extension="$file->extension" class="w-6 h-6" />
Note the x-dynamic-component bridge — you cannot interpolate into a component tag directly, so this is the required escape hatch. Also note aria-hidden="true": icons here are decorative; the filename carries the meaning. If iconography is the only cue for file type, add a screen-reader label instead of hiding it.
Derive the extension defensively. $file->extension is not always populated (S3 paths, extensionless names, uppercase suffixes). Resolve before it reaches the component:
$extension = pathinfo($file->name, PATHINFO_EXTENSION);
Wire it into a table cell. Keep the row cheap — one component call, size, and color from a map you already have:
<td class="flex items-center gap-2">
<x-file-type-icon :extension="$file->extension" />
<span class="truncate">{{ $file->name }}</span>
</td>
Publish and customize. If you need to override artwork or add a file type the package lacks, publish the SVGs into your app and edit them there:
php artisan vendor:publish --tag=blade-file-icons
From that point your copies take precedence locally, which means you have quietly begun forking the set — record that in your dependency notes, because future package updates will not merge into your published copies.
Compose with an existing Blade Icons setup. If the app already uses heroicons or tabler, this is purely additive: same provider mechanism, same rendering path, no version conflicts beyond the shared blade-ui-kit/blade-icons major. Check alignment once with composer show blade-ui-kit/blade-icons.
Stale compiled views are the number one false alarm. Blade caches aggressively. If a component suddenly renders as a literal tag name or nothing at all after a deploy — especially after a Composer update — run php artisan view:clear. This resolves the vast majority of "the package is broken" reports.
Component names are not obvious guesses. The set uses names like file-pdf rather than pdf in some cases and bare names in others. Do not guess from memory; list the directory. A typo in a component name does not throw — Blade renders an empty string or throws a generic "component not found" only under some conditions, so a silent gap can ship to production. Write one test asserting your wrapper renders the expected svg for a handful of extensions, including the fallback.
x-dynamic-component is mandatory for a data-driven icon. <x-fileicon-{{ $icon }} /> is not valid Blade and will fail confusingly if you try to be clever.
Sizing: pass class, and prefer w-5 h-5 over width/height attributes. The SVGs lean on currentColor; color utilities like text-red-600 work, but fill-* generally will not override the internal paths. If you need per-type colors, drive them from the same map that drives the icon name so the two never drift.
Icon-heavy tables. Each component is an inline SVG, which is verbose markup. For a listing of a few dozen rows this is invisible. For hundreds of rows of icons, the accumulated SVG weight shows up in page size and DOM node count. Options, in order of effort: reduce icon density (show icons only for a subset of rows), cache the rendered fragment, or switch to an SVG sprite / CSS background reference for that one hot view. Measure before refactoring — this is usually a non-issue.
Watch the framework constraint, not the code. The package is a view-layer dependency with essentially zero runtime surface, so the actual integration risk is entirely in composer.json: the php floor, the illuminate/* range, and the pinned blade-ui-kit/blade-icons major. New Laravel majors require a maintainer release to widen that range; confirm the tag covers your framework version before planning an upgrade, and pin the package version so an unplanned minor cannot land.
No failure signal exists. A renamed or removed icon in a future release does not throw an exception — it renders nothing, or an empty component. There is no alerting story for missing SVGs, so if the visual is load-bearing anywhere, cover it with the smoke test described above. That test is your only detector.
Exit path is trivially cheap, so plan it and relax. The entire dependency is a folder of SVGs plus a component prefix. If the project stalls, disappears, or an icon's license needs review, publish the SVGs (or copy them from vendor/), keep the <x-file-type-icon> wrapper, and replace the body's x-dynamic-component with a lookup into your own view namespace. Because you centralized the mapping in step one, this is a one-file change across the whole application — which is precisely the reason to build the wrapper on day one rather than after the dependency becomes entrenched.
How can I help you explore Laravel packages today?