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

Blade Gravity Ui Icons Laravel Package

codeat3/blade-gravity-ui-icons

A Laravel Blade component package for Gravity UI icons, letting you render any icon with simple x-icon tags in your Blade views. No SVGs to copy, no config—just clean, inline icon components for your PHP app.

View on GitHub
Deep Wiki
Context7

Getting Started

Install it and render an icon in under a minute

composer require codeat3/blade-gravity-ui-icons

There is nothing else to wire up. No service provider registration, no asset publish, no npm step, no runtime JavaScript. Laravel's package discovery registers the provider, and blade-ui-kit/blade-icons (pulled in as a dependency) handles the actual SVG resolution. The icons land in your templates as Blade components:

<x-gravity-ui-icon-alarm class="w-5 h-5 text-red-500" />

Colour comes from currentColor, so Tailwind's text-* utilities work without touching fill or stroke. Size comes from w-*/h-*. Any HTML attribute you pass (class, aria-label, data-*, id) is forwarded to the root <svg>.

Where to look first, in order

  1. vendor/codeat3/blade-gravity-ui-icons/resources/svg/ — the filename minus .svg is the component suffix. This directory is the authoritative catalogue. README tables drift; the directory does not.
  2. The service provider (BladeGravityUiIconsServiceProvider) — confirms the exact registered prefix (gravity-ui-icon-* is the convention, but verify rather than guess) and shows how the set is registered with Blade Icons.
  3. The config file after publishing — where prefix, a default class, and path overrides live (see below).

First real use case: stop hand-pasting SVG

You were copying <svg> blobs from Figma into Blade files, or maintaining resources/views/components/icons/*.blade.php by hand and forgetting which one was chevron-down vs chevron-down-small. Now:

<button class="inline-flex items-center gap-2 rounded-md bg-blue-600 px-3 py-2 text-white">
    <x-gravity-ui-icon-plus class="w-4 h-4" aria-hidden="true" />
    New item
</button>

The icon inherits the button's white text via currentColor, scales with the button's text size if you use h-[1em], and accepts attributes. Replacing thirty hand-pasted SVGs with thirty component calls is the entire value proposition, and it removes a recurring Figma-to-code chore permanently.

Publish the config only if you need to change the prefix

php artisan vendor:publish --tag=blade-gravity-ui-icons-config

Copy the tag from the README rather than reconstructing it from memory — codeat3 packages follow blade-<set>-config, but that one string is worth verifying. For most projects you never publish this file.

Implementation Patterns

1. Wrap the set once, depend on the wrapper everywhere

The fastest way to waste the benefit of a shared icon set is to sprinkle <x-gravity-ui-icon-*> with ad-hoc sizing across dozens of views — you've reintroduced the fragmentation you just paid a Composer install to remove. Create a single design-system component instead:

{{-- resources/views/components/ui/icon.blade.php --}}
@props(['name', 'size' => 'md'])

@php
    $sizes = [
        'xs' => 'w-3 h-3',
        '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="'gravity-ui-icon-' . $name"
    {{ $attributes->merge(['class' => ($sizes[$size] ?? $sizes['md']) . ' shrink-0']) }}
    aria-hidden="true"
/>

Consumers write <x-ui.icon name="person" size="lg" class="text-gray-400" />. When you swap icon sets, migrate to sprite sheets, or add a data-testid for E2E tests, you edit one file. It also gives you a single place to own the aria-hidden default (see the accessibility gotcha).

2. Data-driven icons via x-dynamic-component

This is the idiomatic seam for nav rails, menu tables, and CMS-driven dashboards:

// config/navigation.php
return [
    ['label' => 'Dashboard', 'route' => 'dashboard', 'icon' => 'house'],
    ['label' => 'Settings',  'route' => 'settings',  'icon' => 'gear'],
    ['label' => 'Reports',   'route' => 'reports',   'icon' => 'chart-line'],
];
@foreach (config('navigation') as $item)
    <a href="{{ route($item['route']) }}" class="flex items-center gap-2">
        <x-dynamic-component :component="'gravity-ui-icon-'.$item['icon']" class="w-4 h-4" />
        {{ $item['label'] }}
    </a>
@endforeach

The icon name comes from a config value written by a developer here, so it's safe. The moment it comes from a request or a user-editable database column, read the injection gotcha below before you ship.

3. Reach for @svg in loops, components everywhere else

Because the set registers through Blade Icons, the set-level helpers work too:

@svg('gravity-ui-alarm', 'w-5 h-5 text-blue-600')

The @svg directive skips Blade component class instantiation and is measurably faster in tight loops — a data table rendering hundreds of rows each with two action icons is exactly where you'd notice. Use components in ordinary templates for readability; use @svg when you're generating markup in bulk.

The svg() helper is the PHP-side escape hatch, useful for notification bodies, mail templates, and array-built table cells:

$html = collect($alerts)->map(fn ($a) => svg(
    'gravity-ui-'.$a['icon'],
    'w-4 h-4 text-'.$a['severity']
)->toHtml());

4. Cache the set on every deploy

Blade Icons compiles the whole SVG directory into a single PHP file, so per-request filesystem reads disappear entirely:

composer install --no-dev --optimize-autoloader
php artisan icons:clear      # see the stale-cache gotcha
php artisan icons:cache
php artisan view:cache
php artisan config:cache
php artisan route:cache

For icon-heavy pages this is the difference between dozens of file reads and one array lookup. For a page with three icons it's noise — but add it to the deploy script unconditionally anyway. Consistent caching beats selective caching you have to remember.

5. Pair it correctly with your stack

  • Tailwind: text-* for colour, w-*/h-* for size. The icons use fill="currentColor" — you almost never need a fill-* utility.
  • Livewire: these are server-rendered Blade components and work fine inside Livewire views. Every Livewire update re-resolves the component, which icons:cache makes cheap — another argument for step 4.
  • Inertia/Vue/React: works only in the root Blade template — the <html> shell, layout chrome, and meta tags. It does not work inside .vue or .jsx templates. For those, use the upstream @gravity-ui/icons JS package.
  • Blade UI Kit / Flux / Heroicons: different prefixes, no conflict. Watch total registered component count if you're on an older Laravel that eagerly resolves them all.

6. Empty states, alerts, and toasts — where consistency earns its keep

Success banner, destructive confirmation, empty search results. One line each, all visually aligned without design review:

<div class="flex items-start gap-3 rounded-lg bg-green-50 p-4">
    <x-gravity-ui-icon-circle-check class="w-5 h-5 text-green-500 shrink-0" aria-hidden="true" />
    <p class="text-sm text-green-800">Saved successfully.</p>
</div>

Gotchas and Tips

Icon names are kebab-cased and must match the filename exactly. Gravity UI's source names are PascalCase (ChevronDown, ArrowUpFromSquare); the package lowercases and hyphenates them (chevron-down, arrow-up-from-square). A wrong name renders nothing — no exception, no placeholder, no console warning. Your first debugging step is always:

ls vendor/codeat3/blade-gravity-ui-icons/resources/svg | grep chevron

This silent-failure mode is the single most-reported "bug" against the entire codeat3/blade-*-icons family. Build the habit: wrong icon → ls the SVG directory, not Stack Overflow.

These are filled paths, not strokes. Gravity UI icons predominantly use fill="currentColor". Adding stroke-red-500 or fill-none does nothing useful, and fill-none in particular can blank the icon entirely. Colour with text-*. If you need a stroked variant, that's a different icon set — not a CSS override.

class merges only onto the root <svg>. You cannot target inner paths from the component call. Arbitrary variants like [&_path]:opacity-50 work if you really must, but if you're fighting per-path specificity you're off the paved road — copy that one SVG into your own registered directory and own it.

User-supplied icon names are an injection surface. :component="'gravity-ui-icon-'.$request->icon" lets a request enumerate or probe arbitrary component names, producing confusing resolution errors and leaking what's installed. Validate against an allowlist:

$icon = in_array($item->icon, config('icons.allowed'), true)
    ? $item->icon
    : 'circle-question';

Better still, type the column as a backed enum and validate at write time — then the template can't go wrong.

icons:cache goes stale on every upgrade. Icons added by a version bump won't appear, and — worse — icons removed by a version bump keep rendering from the old cache file. This is the classic Friday-afternoon time-sink: you install 1.4.0, the changelog says "Laravel 13 compatibility," and suddenly new icons don't resolve. The fix is always:

php artisan icons:clear && php artisan icons:cache

Bake the clear into the deploy script ahead of the cache, unconditionally.

Silent "component not found" right after install. In order of likelihood:

php artisan view:clear
php artisan optimize:clear
composer dump-autoload

Package discovery caches metadata in bootstrap/cache/packages.php. If you installed with --no-scripts, or that cache predates the install, the provider never registers — and Laravel does not error loudly on an unknown x-unknown-component; it renders an empty string. If optimize:clear doesn't fix it, confirm registration directly:

cat bootstrap/cache/packages.php | grep gravity

Prefix collisions with your own components. If resources/views/components/ contains a file that shadows gravity-ui-icon-alarm, the app component wins and you get a confusing render with missing classes or wrong paths. grep -r "gravity-ui-icon" resources/views/ will find offenders. Publishing the config and renaming the prefix is cheaper than auditing every shadowed name.

Accessibility is your responsibility — the component adds no ARIA. Two cases, and they're different:

{{-- Decorative: hide from assistive tech --}}
<x-gravity-ui-icon-plus class="w-4 h-4" aria-hidden="true" focusable="false" />

{{-- Meaningful: label the BUTTON, hide the ICON --}}
<button type="button" aria-label="Delete record">
    <x-gravity-ui-icon-trash-bin class="w-4 h-4" aria-hidden="true" />
</button>

Note the pattern: the label goes on the interactive element, the icon gets aria-hidden. Don't put role="img" + aria-label on an icon inside an already-labelled button — screen readers will announce it twice. focusable="false" is legacy IE/Edge insurance; harmless to keep.

Watch the vendor risk, and note how cheap the mitigation is. Zero stars, zero dependents, single maintainer, largely automated release cadence. The failure mode is benign — MIT licence, and the payload is just SVG files — but it's still a solo-maintained package. The entire dependency is resources/svg/ plus a ~50-line service provider. If this becomes load-bearing:

  1. Copy vendor/codeat3/blade-gravity-ui-icons/resources/svg/ to resources/svg/gravity-ui/.
  2. Register the set yourself:
public function boot(): void
{
    BladeIcons::registerIcon('gravity-ui-*', resource_path('svg/gravity-ui'));
}
  1. composer remove codeat3/blade-gravity-ui-icons.

Ten minutes of work, and the dependency disappears. Do it before you discover a missing icon on a Friday, not after. Bonus: adding a new icon afterwards is a cp from the upstream repo, with no Composer release cadence in the loop.

Extension point, with a caveat. The package's icon class extends BladeUI\Icons\Svg, which is the seam for global post-processing — stripping hardcoded width/height, injecting aria-hidden, rewriting currentColor. But a custom icon class means losing the benefit of icons:cache, which was the whole performance argument. Prefer doing transformations in your wrapper component (Pattern 1): same seam, none of the cache penalty.

Pin to a minor. With 1.4.0 landing Laravel 13 compatibility, the package tracks framework majors, which is good. But the release cadence is largely automated, and the diff between a working and broken icon component is often just a regenerated SVG directory. "codeat3/blade-gravity-ui-icons": "^1.4" and let the lock file do its job — don't chase patch releases unless you need a specific icon.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource