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

Svg Inliner Laravel Package

vierwd/svg-inliner

A Laravel package for inlining SVG images directly into your HTML, letting you style and animate them with CSS and control their colors. Useful for icons and illustrations where external image references would block styling. Lightweight and easy to integrate.

View on GitHub
Deep Wiki
Context7

Getting Started

vierwd/svg-inliner is a small, single-purpose utility: it takes an SVG file and returns the raw <svg>…</svg> markup so you can embed it directly in your HTML instead of loading it via <img> or background-image. That unlocks CSS control over fill/stroke, currentColor, and per-instance hover/focus states without juggling multiple icon files.

Install it like any Composer package:

composer require vierwd/svg-inliner

There is no service provider and (almost certainly) no Laravel auto-discovery — it's framework-agnostic PHP, so nothing appears in config/app.php. Before writing integration code, open vendor/vierwd/svg-inliner/src/ and read the class. The surface area is tiny (a handful of static methods at most), and knowing the exact signature — whether it accepts a path, a string, or both — saves you guessing.

First use case, done the simplest way possible:

use Vierwd\SvgInliner\SvgInliner; // verify the namespace in src/

$svg = SvgInliner::inline(resource_path('images/logo.svg'));
{{-- Blade will escape it, so print raw and trust the source file --}}
{!! $svg !!}

A more realistic starting point in Laravel is a Blade component so templates stay clean:

{{-- resources/views/components/icon.blade.php --}}
@props(['name', 'class' => ''])
<svg-inline {{ $attributes->merge(['class' => $class]) }}>
    {!! $svg !!}
</svg-inline>

If the package only exposes a function or a non-static class, wrap it once in your own Icon helper and never call the package directly from views. That single indirection layer is the difference between "easy to swap later" and "grep the whole codebase" — worth it for a package with one star and a 2022 release date.

Start with one icon, verify fill="currentColor" behaves, then roll it out.

Implementation Patterns

Blade component + a caching layer. Reading and sanitizing a file on every render is wasteful on a page with twenty icons. Cache the parsed markup keyed by path and mtime:

class IconRenderer
{
    public function render(string $path): string
    {
        $full = resource_path("images/icons/{$path}.svg");

        return Cache::remember(
            'svg:'.md5($full).':'.filemtime($full),
            now()->addDay(),
            fn () => SvgInliner::inline($full),
        );
    }
}

Binding this as a singleton in a service provider keeps views dumb and makes the caching strategy testable and swappable.

SVG sprite / symbol mode for icon-heavy UIs. Inlining the same icon fifty times bloats the DOM and duplicates gradient/clip IDs. For a design system, an alternative pattern is to inline a single hidden <svg> sprite at the top of <body> and reference symbols with <use href="#icon-name">. If the package doesn't do sprite generation, use it to load the source files and assemble the sprite yourself in a scheduled command or a @php block in your layout. Inlining individual icons is fine for a handful; it does not scale to a full icon set per page.

currentColor discipline. The whole point of inlining is styling. Audit your source SVGs and normalize fill to currentColor (or none with stroke="currentColor") so Tailwind's text-* utilities control color:

<x-icon name="check" class="w-5 h-5 text-green-600" />

If you can't edit the source files, post-process the returned string with a targeted str_replace on fill="#..." — but do it centrally in your renderer, not scattered through views.

Build-time inlining for static pages. If your icons rarely change, inline them into a cached Blade view or a generated partial during deploy. This turns runtime file I/O into zero cost and sidesteps the cache entirely.

Testing. Assert on the rendered markup rather than the package internals:

$response = $this->get('/');
$response->assertSee('<svg', false);
$response->assertDontSee('<?xml');

If the package exposes a deterministic string transform, unit-test your wrapper against a fixture SVG. Do not build tests that assert the package's own behavior — with 1 star and no releases since late 2022, pin the version in composer.json and treat the library as frozen.

Gotchas and Tips

XML prolog and DOCTYPE leakage. Most naive inliners wrap the file contents in file_get_contents() and strip <?xml … ?>. Check that the package handles the prolog, <!DOCTYPE svg>, comments, and leading whitespace — a stray <?xml version="1.0"?> inside your HTML body is invalid markup and will trip HTML validators and some SSR hydration paths. If it doesn't strip them, do it in your wrapper with a regex on the first line only.

ID collisions are the classic inline-SVG bug. Two inlined SVGs containing <linearGradient id="a"> will collide in the shared document scope, and the second icon will silently render with the first one's gradient. If your icons have internal IDs, namespace them per-render:

$svg = preg_replace_callback(
    '/id="([^"]+)"/',
    fn ($m) => 'id="'.$prefix.'-'.$m[1].'"',
    $svg,
);

…and update the matching url(#…) / xlink:href="#…" references in the same pass. This is the single most common reason inlined icons look "broken" on some pages but fine on others.

Hardcoded width/height beat your CSS. An SVG with width="24" height="24" and no viewBox won't scale. Prefer source files with viewBox only, and add width/height via your Blade component's attribute bag. Conversely, if a source has neither, the SVG collapses to zero size — hence the viewBox requirement.

<style> blocks inside SVGs leak globally. An inline <style>.cls-1{fill:red}</style> is scoped to the whole document once inlined, not just that SVG. Strip <style> tags from source files and move styling into your CSS layer, or convert classes to presentation attributes.

Never inline untrusted SVGs. SVG is XML with script support: <script>, onload=, and external xlink:href references are all live XSS vectors. This package is a formatting utility, not a sanitizer. For anything user-uploaded, run it through a dedicated sanitizer or rasterize it. Icons from your own repo are fine.

Path resolution differs from URL paths. resource_path() / base_path() work; public_path('/images/x.svg') may not exist if you use Vite or a CDN. Pass absolute filesystem paths into the package, and resolve them in one place so moving assets (e.g., into a package) is a one-line change.

Caching needs mtime, not just path. A cache key of only the icon name means edited SVGs stay stale until you clear the cache. Including filemtime() in the key makes deploys self-invalidating; for rememberForever keys, hook a php artisan cache:clear into your deploy script.

Extension points are minimal — lean on your wrapper. With a tiny dependency, don't fork it to add features. Put the sanitizing, ID-namespacing, caching, and CSS-class injection in your own IconRenderer/Blade component. Then replacing vierwd/svg-inliner with a few lines of file_get_contents + DOMDocument, or a more actively maintained package, is a localized change.

Watch for DOMDocument failure modes if you post-process. loadXML() emits warnings on valid-but-loose SVG and returns false on malformed files, and it re-encodes entities. Suppress warnings with libxml_use_internal_errors(), or use string manipulation for simple transformations.

License and maintenance posture. MIT, so forking and vendoring are unproblematic. Last release November 2022 and no dependents means no upstream fixes are coming — pin the version with a caret on the exact minor, and if you end up with more than ~20 lines of wrapper logic, consider dropping the dependency altogether. For a package this small, the wrapper you write for Laravel is often the more valuable artifact.

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