Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

File Icon Vectors Laravel Package

dmhendricks/file-icon-vectors

A PHP library that maps file extensions to crisp SVG icons, making it easy to display accurate file-type icons for documents, media, archives, and more. Includes multiple icon styles, simple helper methods, and Laravel support for quick integration.

Deep Wiki
Context7

Getting Started

dmhendricks/file-icon-vectors is not a Laravel package — there is no service provider, no facade, no config file, no auto-discovery. It is a Composer-installed folder of SVG icons plus pre-built CSS that maps .fiv-icon-{extension} classes to those SVGs. Treat it as a static asset dependency.

1. Install

composer require dmhendricks/file-icon-vectors

2. Look at what you actually got

ls vendor/dmhendricks/file-icon-vectors/dist
ls vendor/dmhendricks/file-icon-vectors/dist/css

You will find the icon sets (classic, vivid, square-outline), a combined stylesheet, and an icons/ directory. Confirm the exact filenames here before writing any <link> tag — the CSS filenames have changed shape across releases.

3. Publish the whole dist/ folder into the webroot

Because vendor/ is not served by the web server, add a tiny provider (see Implementation Patterns) or, for a one-off:

cp -R vendor/dmhendricks/file-icon-vectors/dist public/vendor/file-icon-vectors

4. First use case — an icon next to a filename

{{-- resources/views/layouts/app.blade.php --}}
<link rel="stylesheet"
      href="{{ asset('vendor/file-icon-vectors/css/file-icon-vectors.min.css') }}">
<span class="fiv-cla fiv-icon-pdf" aria-hidden="true"></span>
Report.pdf

The pattern is fiv-{set} + fiv-icon-{extension}. Sets are fiv-cla (classic), fiv-viv (vivid), fiv-sqo (square outline). The set class is also the base class — it supplies the inline-block, dimensions and background-size — so both classes are required.


Implementation Patterns

Pattern 1: A publishable provider (recommended)

// app/Providers/FileIconVectorsServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class FileIconVectorsServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $source = base_path('vendor/dmhendricks/file-icon-vectors/dist');

        if (! is_dir($source)) {
            return; // package not installed (e.g. --no-dev in some CI images)
        }

        $this->publishes([
            $source => public_path('vendor/file-icon-vectors'),
        ], 'file-icon-vectors');
    }
}

Then php artisan vendor:publish --tag=file-icon-vectors --force becomes a required step in your deploy script. Add it next to config:cache:

composer install --no-dev --optimize-autoloader
php artisan vendor:publish --tag=file-icon-vectors --force
php artisan config:cache

The --force matters: without it, a second deploy will not refresh the assets.

Pattern 2: Normalise extension → icon name

Icons are keyed by file extension, not MIME type. Your storage layer gives you MIME types, so you need a resolver, and you need aliases because the SVG set only ships one spelling per family.

// app/Support/FileIcon.php
namespace App\Support;

class FileIcon
{
    /** Extensions the icon set lacks or spells differently. */
    private const ALIASES = [
        'jpeg' => 'jpg',
        'htm'  => 'html',
        'tif'  => 'tiff',
        'yaml' => 'yml',
        'mpeg' => 'mpg',
    ];

    private const MIME_MAP = [
        'application/pdf' => 'pdf',
        'application/zip' => 'zip',
        'text/plain'      => 'txt',
        'text/csv'        => 'csv',
    ];

    public static function fromPath(?string $path, ?string $mime = null): string
    {
        $ext = strtolower(pathinfo((string) $path, PATHINFO_EXTENSION));

        if ($ext === '' && $mime !== null) {
            $ext = self::MIME_MAP[$mime] ?? '';
        }

        $ext = self::ALIASES[$ext] ?? $ext;

        return $ext !== '' ? $ext : 'blank';
    }
}

Discover the real inventory instead of guessing:

grep -o 'fiv-icon-[a-z0-9]*' \
  vendor/dmhendricks/file-icon-vectors/dist/css/file-icon-vivid.min.css \
  | sed 's/.*fiv-icon-//' | sort -u | tr '\n' ' '

Pattern 3: A Blade component

// app/View/Components/FileIcon.php
namespace App\View\Components;

use App\Support\FileIcon as Resolver;
use Illuminate\View\Component;

class FileIcon extends Component
{
    public string $extension;

    public function __construct(
        public ?string $path = null,
        public ?string $mime = null,
        public string $set = 'viv',
        public string $size = '1em',
    ) {
        $this->extension = Resolver::fromPath($path, $mime);
    }

    public function render()
    {
        return view('components.file-icon');
    }
}
{{-- resources/views/components/file-icon.blade.php --}}
<span class="fiv-{{ $set }} fiv-icon-{{ $extension }}"
      style="width: {{ $size }}; height: {{ $size }};"
      aria-hidden="true"
      {{ $attributes }}></span>
<x-file-icon :path="$document->filename" size="1.5rem" class="mr-2" />

<x-file-icon :path="$upload->path" :mime="$upload->mime_type" set="sqo" />

Pattern 4: Rendering in tables / file browsers

Use the icon as decoration only — the filename text stays the accessible label:

<td class="flex items-center gap-2">
    <x-file-icon :path="$file->name" />
    <a href="{{ route('files.download', $file) }}">{{ $file->name }}</a>
</td>

Because the base class sets a fixed width/height (typically 1em), you can scale the whole thing by setting font-size on a parent instead of overriding width/height. That keeps the icon square and avoids fighting Tailwind:

<span class="text-2xl"><x-file-icon :path="$file->name" set="cla" /></span>

Pattern 5: Only ship the set you use

If you standardise on one set, link the per-set stylesheet rather than the combined bundle — it is a meaningfully smaller CSS payload and it is the only real performance lever you have with this package.

<link rel="stylesheet"
      href="{{ asset('vendor/file-icon-vectors/css/file-icon-vivid.min.css') }}">

Pattern 6: Serving the CSS through Vite (when you must)

Vite is the default in modern Laravel, and vendor/ is outside its scope. Two workable options:

  • Preferred: keep public/vendor/file-icon-vectors/ as a published static asset and reference it with asset(). Simple, cache-busted with ?v= if you care.
  • Alternative: copy dist/ into resources/ and @import the CSS from app.css. This works only if you also copy the icons and preserve the relative directory depth, because the CSS references ../icons/... — Vite will try to resolve those URLs at build time.

Do not @import a stylesheet whose url() paths point into vendor/; you get build errors or silently broken icons.


Gotchas and Tips

The whole dist/ tree must move together. The CSS resolves icons relatively (../icons/...). Copying only the .css file into public/css/ gives you a page of empty boxes and a Network tab full of 404s. Publish dist/ as a directory, preserving its internal structure.

No auto-discovery, no config. composer require alone does nothing visible in a Laravel app. If you forget the publish step, the classes exist in your markup but no stylesheet defines them — the span collapses to zero width and you spend twenty minutes wondering why the layout shifted.

The package is frozen at 2018. This is the single biggest caveat. Expect missing modern extensions (heic, avif, webp, ts/tsx, various *x variants, newer Office/design formats). Verify your top extensions exist before designing around the package:

for e in webp avif heic ts docx xlsx; do
  grep -q "fiv-icon-$e" vendor/dmhendricks/file-icon-vectors/dist/css/file-icon-vivid.min.css \
    && echo "ok   $e" || echo "MISS $e"
done

Keep a fallback (fiv-icon-blank, or your own generic SVG) and consider forking the CSS if a handful of extensions are systematically missing.

Extension ≠ MIME type. image/jpeg is ambiguous between jpg and jpeg; text/x-yaml and application/yaml are both yaml. Always normalise through an alias map, and prefer the filename extension over the MIME type when you have both.

Uppercase extensions break silently. Report.PDF yields fiv-icon-PDF, which no rule matches. strtolower() in one place, always.

Framework resets can break the base class. The fiv-* base class relies on display, width, height and background-size. A Tailwind preflight, Bootstrap reboot, or a span { display: inline } rule from your own CSS can override it because these are single-class selectors. If icons render at the wrong size, inspect computed styles on the span first — it is almost always a reset, not the package.

Don't fight the sizing with utility classes. Setting w-6 h-6 directly on the span usually loses to the package's own width/height or produces a stretched icon. Drive the size via font-size on the parent or an inline style, as in the component above.

Accessibility. These are decorative. Always emit aria-hidden="true" and never let the icon be the only signal of file type — screen readers get nothing from fiv-icon-xlsx. Pair with the filename or an explicit label.

Deployment ordering. vendor:publish is not run by composer install. If your deploy pipeline only runs composer install && artisan migrate, the icons will 404 in production even though they worked locally — locally they were probably published months ago and the files are sitting in public/ (possibly gitignored).

Cache the grep, not the discovery. If you build a dropdown of selectable file types from the icon inventory, do the grep once at build time and commit the resulting list; do not shell out to grep at request time.

Where to extend: there is no extension point, but the CSS is trivially forkable. For a missing extension, add a rule pointing at a generic SVG:

/* app/overrides/file-icon-vectors.css — loaded after the package CSS */
.fiv-viv.fiv-icon-webp { background-image: url("/vendor/file-icon-vectors/icons/vivid/image.svg"); }

That is the pragmatic escape hatch for a package that will not be updated. If the missing-extension list grows past a handful, switch to a maintained alternative (the file-icon-vectors npm package, devicon, or inline SVGs via <x-icon>) rather than maintaining a fork of a dead asset set.

Debugging checklist, in order: (1) does View Source show the <link>? (2) does the CSS URL return 200? (3) do the icon URLs inside the CSS return 200? (4) does the class name exactly match a rule (grep fiv-icon-yourtype)? (5) is the element's computed width/height zero? Ninety percent of issues are step 2 or step 4.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin