codeat3/blade-gala-icons
A Blade component package that brings the Gala icon set to Laravel. Render any Gala icon in your Blade views with a simple, expressive tag, keeping SVG markup clean and consistent while adding crisp icons to your UI with minimal effort.
Install (no config required)
composer require codeat3/blade-gala-icons
The service provider is auto-discovered. There is nothing to publish, no assets to compile, no JS. Icons are inline SVG rendered server-side.
First place to look: the icon inventory, not the docs. Icon names map to filenames, so browse the shipped catalogue before writing any markup:
ls vendor/codeat3/blade-gala-icons/resources/svg | head -50
ls vendor/codeat3/blade-gala-icons/resources/svg | wc -l # know your coverage before committing
A file named arrow-right.svg becomes <x-gala-arrow-right />. Every component is prefixed gala- to keep it out of the way of other icon sets.
First use case: replace a hand-rolled SVG in a nav item or empty state.
<x-gala-star class="w-6 h-6 text-indigo-500" />
That is the whole workflow: composer require, then a Blade tag. Sizing and colour are just Tailwind utilities because the root <svg> inherits currentColor and the component accepts arbitrary attributes.
If you already use blade-ui-kit/blade-icons (Heroicons, Tabler, etc.), you already have the runtime — this package only adds a set to it. If you don't, it comes in as a transitive dependency and gives you @svg() and php artisan icons:cache for free.
First 30 minutes well spent: migrate 5–10 real icons on a throwaway branch and screenshot-diff the pages. Swapping icon families shifts viewBox, stroke width, and default fill — regressions show up visually, never in a code diff.
1. Direct component rendering — the default
<x-gala-arrow-right class="w-4 h-4" />
<x-gala-trash class="w-4 h-4 text-red-600" />
Additional attributes land on the root <svg>, so aria-hidden, role, stroke-width, fill all pass through.
2. The @svg() directive — when you need it in a string context
Because this sits on blade-icons, the directive form works too. The set prefix becomes the first name segment:
@svg('gala-star', 'w-6 h-6 text-indigo-500')
Use this when you're composing inside a PHP expression, a @php block, or a mail template string that can't cleanly hold a component tag. Prefer the component form elsewhere — it's more idiomatic and easier to grep.
3. Dynamic names from data — the pattern you'll actually need
A nav menu or status map almost always stores an icon name in config or the database. Use x-dynamic-component, never string interpolation into a tag:
{{-- config/navigation.php --}}
['label' => 'Dashboard', 'icon' => 'star', 'route' => 'dashboard'],
@foreach (config('navigation') as $item)
<a href="{{ route($item['route']) }}" class="flex items-center gap-2">
<x-dynamic-component :component="'gala-'.$item['icon']" class="w-5 h-5 text-slate-500" />
<span>{{ $item['label'] }}</span>
</a>
@endforeach
4. Wrap it once — a design-system component
Don't let 40 call sites each pick their own size. Wrap the set the day you adopt it, so future icon-set changes are a one-file edit:
{{-- resources/views/components/icon.blade.php --}}
@props(['name', 'size' => 'md'])
@php
$sizes = ['sm' => 'w-4 h-4', 'md' => 'w-5 h-5', 'lg' => 'w-6 h-6', 'xl' => 'w-8 h-8'];
@endphp
<x-dynamic-component
:component="'gala-'.$name"
{{ $attributes->class($sizes[$size] ?? $sizes['md']) }}
aria-hidden="true"
/>
Call sites then read <x-icon name="star" size="lg" class="text-indigo-500" />. $attributes->class() merges rather than overwrites, which matters the first time someone passes class="rotate-90".
5. Accessible icon buttons
An inline SVG is not a label. Pair it with text, or hide the icon and label the control:
<button type="button" class="p-2 rounded hover:bg-slate-100">
<x-gala-trash class="w-5 h-5" aria-hidden="true" />
<span class="sr-only">Delete record</span>
</button>
Add aria-hidden="true" by default in your wrapper — an inline <svg> inside a button otherwise gets announced as an unlabeled graphic in some screen readers.
6. Caching for production builds
blade-icons can precompile the set instead of parsing SVG files per request:
php artisan icons:cache # in your deploy script, after config:cache
php artisan icons:clear # locally, when you add/rename icons
Pair this with php artisan view:clear after any package upgrade — compiled Blade components are not invalidated automatically.
7. Testing that icons resolve
A typo'd component name is the most likely defect in this integration, and it's invisible until someone eyeballs the page. Add both a smoke test and a catalogue sweep so a package upgrade can't silently drop icons:
it('renders the gala icon set', function () {
expect(Blade::render('<x-gala-star />'))->toContain('<svg');
});
it('resolves every shipped gala icon', function () {
$files = File::files(base_path('vendor/codeat3/blade-gala-icons/resources/svg'));
foreach ($files as $file) {
$name = 'gala-' . Str::kebab($file->getFilenameWithoutExtension());
expect(Blade::render("<x-dynamic-component :component=\"'{$name}'\" />"))
->toContain('<svg');
}
});
That second test is the cheapest possible guard against a bus-factor-1 dependency breaking your UI.
8. Emails and PDFs
Blade mail templates render these fine as markup, but Gmail strips inline SVG from HTML email. For transactional email, export PNGs and use <img>, or accept that Outlook/Gmail recipients see nothing. Inside DomPDF/Snappy, inline SVG works only if the renderer supports it — test before shipping.
Name resolution is the failure mode, not PHP errors. An unresolvable component surfaces as an exception in a dev request, but in a rendered-and-cached production path a bad name is easy to ship as blank space. Treat the catalogue sweep test above as mandatory, and pin the version so an upstream rename can't reach you silently: "codeat3/blade-gala-icons": "^1.4".
Prefix collisions are real if you mix sets. <x-gala-*> is unlikely to clash, but running Gala alongside Heroicons/Tabler means three icon families, three viewBox conventions, and inconsistent visual weight. Pick one family per surface and document it — otherwise the design review happens in production.
Attribute precedence is not always what you expect. Attributes you pass land on the root <svg>, but many icon files already hardcode fill="none" or stroke="currentColor" on the root or on child paths. If text-red-600 doesn't tint an icon, the file has a literal colour inside it. Inspect the actual SVG:
grep -l 'fill="#' vendor/codeat3/blade-gala-icons/resources/svg/*.svg
Sizing: prefer Tailwind classes over a size attribute. class="w-5 h-5" is deterministic; a bare size="20" renders as a non-standard attribute on the <svg> element and does nothing. If you want a size prop, implement it in your own wrapper (see pattern 4).
Don't build class names dynamically. "w-{$size}" defeats Tailwind's scanner and the icon renders at its intrinsic size in production only. Use a lookup array, as in the wrapper above.
Publishing config is opt-in and rarely needed. Only reach for it if you want to change the prefix, register a custom set path, or set a default icon. The tag belongs to blade-icons, not this package:
php artisan vendor:publish --tag=blade-icons-config
Adding a set there means also registering the path yourself — you're better off letting auto-discovery work unless you have a specific reason.
Cached icons ignore your edits. If you've run icons:cache and then changed a config value or upgraded the package, the old markup persists until php artisan icons:clear. This is the #1 "why is my icon still wrong" moment.
Payload cost is per-instance. Inline SVG means zero extra HTTP requests but no browser cache and duplicated markup — a 50-row table with an icon per row ships 50 copies of that icon's paths. For dense, high-traffic public pages, consider a sprite or a cached partial; for admin screens and app shells, inline is the right call.
Upgrades are cheap — verify them anyway. The 1.4.x line exists to widen constraints for Laravel 13 with no API changes, but the release notes carry no visible CI matrix. Before adopting on your framework version:
composer why-not codeat3/blade-gala-icons ^1.4
composer update --dry-run codeat3/blade-gala-icons
Also confirm which blade-icons major it pins, and that it matches what any other icon package already requires — two packages needing different majors is the most likely install blocker.
Licensing lives one level down. The Composer package is MIT; the vendored Gala SVGs carry the upstream set's own terms. If you ship a client deliverable or a public repo, read the upstream licence before your first commit rather than after — retrofitting attribution into shipped pages is expensive.
Document the escape hatch now. Single maintainer, zero dependents. The icons are plain SVG files in vendor/. If the package stalls, forking it (or copying resources/svg into your own blade-icons set) is an afternoon, not a migration. Write that down while it's still hypothetical.
Extension points worth knowing: the gala prefix via published config, your own wrapper component for sizing/accessibility defaults, icons:cache for build-time precompilation, and blade-icons' set registration if you ever need to merge in-house SVGs alongside the vendor set under one prefix.
How can I help you explore Laravel packages today?