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 Radix Icons Laravel Package

codeat3/blade-radix-icons

A Laravel Blade package for rendering Radix Icons as simple, customizable components. Use convenient x-radix-icon tags in your views, with support for sizing, colors, and easy Composer installation.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require codeat3/blade-radix-icons

That's the entire install. The service provider is auto-discovered, there is nothing to publish, no config file to author, no npm package, no build step, no asset compilation. If you have ever added a blade-* icon pack before, this is the same ritual.

Where to look first

  1. vendor/codeat3/blade-radix-icons/resources/svg/ — this directory is the API. Every .svg filename maps directly to a component name. Don't trust a README icon list; trust the filesystem, because it's the only thing guaranteed to match the installed version:

    ls vendor/codeat3/blade-radix-icons/resources/svg | sed 's/\.svg$//' | column -c 100
    
  2. The service provider (src/RadixIconsServiceProvider.php) registers the set with the radix prefix — that's why the component is <x-radix-* /> and the directive form is @svg('radix-*'). Read those ten lines once and you'll never wonder about naming again.

  3. Upstream catalogue at https://www.radix-ui.com/icons for visual browsing — but cross-check the name against the vendor directory, since upstream renames trickle in on the package's own schedule.

First use case

The fastest path to value is a sidebar/nav or a set of action buttons where you currently paste raw SVG or fight an icon font:

<nav class="space-y-1">
    <a href="/dashboard" class="flex items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
        <x-radix-dashboard class="size-4 shrink-0 text-gray-500" aria-hidden="true" />
        <span>Dashboard</span>
    </a>
    <a href="/settings" class="flex items-center gap-2 rounded px-3 py-2 hover:bg-gray-100">
        <x-radix-gear class="size-4 shrink-0 text-gray-500" aria-hidden="true" />
        <span>Settings</span>
    </a>
</nav>

Smoke-test it in a scratch route or php artisan tinker-adjacent blade partial before wiring it into real views. If the icons render at 15px and inherit your text color, the whole package is working — everything after that is styling.


Implementation Patterns

Sizing and color

Radix glyphs are drawn on a 15×15 grid and use currentColor, so they inherit text-* automatically. Control size with CSS classes, not attributes:

<x-radix-magnifying-glass class="size-4 text-gray-400" />   {{-- 16px --}}
<x-radix-check class="size-5 text-green-600" />             {{-- 20px --}}
<x-radix-cross-2 class="size-3 text-red-500" />             {{-- 12px --}}

Tailwind's w-*/h-*/size-* are CSS properties and win over the SVG's intrinsic width="15" height="15" presentation attributes. Prefer size-4 (16px) or size-5 (20px) over arbitrary 15px — that's the grid the set was optically tuned for.

A semantic wrapper component (the pattern that pays off)

Do not let <x-radix-* /> spread across 300 views. Map your app's vocabulary to the icon set once:

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

@php
    $map = [
        'search'    => 'magnifying-glass',
        'edit'      => 'pencil-1',
        'delete'    => 'trash',
        'settings'  => 'gear',
        'dashboard' => 'dashboard',
        'close'     => 'cross-2',
        'next'      => 'chevron-right',
    ];
    $icon = $map[$name] ?? throw new InvalidArgumentException("Unknown icon [{$name}].");
@endphp

<x-dynamic-component :component="'radix-'.$icon" class="{{ $size }} shrink-0" {{ $attributes }} />

Now a swap of icon sets (or a move to vendored SVGs) is one file, and a typo is a loud 500 in dev rather than a silent blank.

Accessibility: two shapes, decided at the call site

{{-- Decorative: redundant with adjacent text --}}
<x-radix-check class="size-4" aria-hidden="true" />
<span>Saved</span>

{{-- Meaningful standalone: label it yourself --}}
<button type="button" class="rounded p-2 hover:bg-gray-100">
    <x-radix-trash class="size-4" aria-hidden="true" />
    <span class="sr-only">Delete project</span>
</button>

The package emits no title, no role, no focusable. Prefer the sr-only pattern over aria-label on the <svg> — screen-reader support for labelled inline SVG is inconsistent, and the <button> already carries the semantics.

Dynamic names

Two supported forms; pick one and be consistent:

{{-- Directive form: works with a computed string --}}
@svg('radix-'.$status, 'size-4 text-gray-500')

{{-- Component form: needs the dynamic component wrapper --}}
<x-dynamic-component :component="'radix-'.$status" class="size-4" />

If the name comes from user input, a database column, or anything else untrusted, resolve it through a whitelist (or the map above). Arbitrary string interpolation into a component name is how you get "icon renders blank, nobody knows why" tickets.

Common day-to-day placements

  • Table row actions — pencil-1 (edit), trash (delete), copy (duplicate), with size-4 and text-gray-400 hover:text-gray-700.
  • Empty states — one large size-10 text-gray-300 glyph above the copy (inbox, file-text, magnifying-glass).
  • Form field affordances — magnifying-glass inside a search input, chevron-down on <select>, cross-circled for clear buttons.
  • Status pills — check-circled / exclamation-triangle / info-circled at size-3.5 next to a label.
  • Buttons with leading icons — always shrink-0 so the glyph doesn't squash in a flex row.

Testing that icons actually render

Missing icons fail silently, so assert on markup in a smoke test:

public function test_icon_components_render(): void
{
    $this->blade('<x-radix-check />')
        ->assertSee('<svg', false)
        ->assertSee('viewBox="0 0 15 15"', false);

    $this->blade('@svg("radix-arrow-left", "size-4")')
        ->assertSee('<svg', false);
}

Better: keep a config/icons.php (or the map from the wrapper component) listing every icon your app uses, and loop the test over it. That config is also your migration checklist if you ever vendor the SVGs.

Migration from inline SVGs

The components are self-contained, so replacement is mechanical and incremental — no controllers, no models, no asset pipeline:

  1. Grep for <svg in resources/views.
  2. For each partial, find the matching Radix name in the vendor directory.
  3. Replace, keep the same sizing classes, delete the partial.
  4. Run php artisan view:clear and eyeball the pages.

Leave icon-fonts alone until last; mixing a font and components on one screen surfaces alignment inconsistencies that aren't worth debugging twice.

Deploys

Icon resolution happens at view-compile time, so ordering matters:

composer install --no-dev --optimize-autoloader
php artisan view:cache      # must come AFTER composer install
php artisan config:cache

After a package upgrade that adds icons, php artisan view:clear locally — Blade caches compiled components and stale caches make new icons look missing.


Gotchas and Tips

A wrong icon name renders nothing — no exception, no warning. This is the single most common failure and it never shows up in CI. Two mitigations: (a) the wrapper component above that throws on unknown names, and (b) blade-ui-kit/blade-icons has a fallback setting — publish its config, point fallback at a very obvious placeholder glyph, and typos become visually loud:

php artisan vendor:publish --provider="BladeUI\Icons\BladeIconsServiceProvider"
// config/blade-icons.php
'fallback' => 'radix-question-mark',

Caveat: publishing that config means you own it, and future blade-icons config keys won't arrive automatically. Publish only if you actually need the fallback or a global default class.

Component names are kebab-case filenames, including numeric suffixes. cross-2, chevron-down, arrow-left, pencil-1, text-align-left. There is no IDE autocompletion for these — maintain your map/config and treat it as the source of truth. Watch for near-duplicates that differ only by suffix.

The blade-icons.php class key applies to every registered icon set, not just Radix. If you set 'class' => 'size-4' globally and later add Heroicons, both sets change. Scope sizing in your own wrapper component instead.

15px is the design size. Radix icons are optimized for a 15px box; scaling to 24px+ is legitimate (vectors scale perfectly) but optical weight thins out. If your design system runs a 24px baseline, prefer a neighboring set sized for it, or accept slightly light strokes at size-6.

view:cache before composer install = blank icons in production only. This is the classic deploy-ordering bug: local dev works, prod ships empty <svg> shells or missing elements. Put the ordering in your deploy script and never debug it twice.

Blade caching bites during upgrade. After bumping the package, an old compiled view can mask newly added icons. php artisan view:clear is the first reflex for "the icon exists in vendor but renders blank."

Attribute binding in Blade has sharp edges. <x-radix-check :class="$active ? 'text-green-600' : 'text-gray-400'" /> works; so does merging {{ $attributes }} in a wrapper. But aria-hidden="{{ $decorative ? 'true' : 'false' }}" produces aria-hidden="false" which is technically an anti-pattern — omit the attribute entirely for meaningful icons rather than setting it false.

Inline SVG volume is real on icon-dense pages. Fifty table rows × three inline SVGs is 150 extra DOM nodes per render. For most admin screens this is invisible; for a paginated 100-row table with per-row actions, measure before optimizing. If it does show up: reduce icon count, drop to a single glyph per row, or check whether the installed blade-icons version exposes php artisan icons:cache (php artisan list | grep icons) and fold it into your deploy alongside view:cache. Verify the command's behavior on your version rather than assuming — the caching/sprite story has changed across blade-icons major versions.

Radix is a monochrome utility set. There's no multi-color, no illustrative, no brand iconography here. If design asks for a colored logo mark, don't fight the set — put a real asset in place and keep this package for UI chrome.

Verify the framework resolution, not just the package version. 1.9.0 declares Laravel 13 support, but the real constraint lives in blade-ui-kit/blade-icons. Before you upgrade the framework:

composer require codeat3/blade-radix-icons:^1.9 --dry-run -W

Read the full dependency delta. If blade-icons lags, pin one version back rather than force-resolving — a presentation-layer package should never be the reason a framework upgrade stalls.

Single maintainer, zero dependents. Caret-pin the version, commit the lockfile, let Dependabot/Renovate open the bumps, and don't build deep customization on top of it. Because the components are thin wrappers over MIT SVGs, the exit is genuinely mechanical: copy resources/svg into your own tree, keep your wrapper component's map intact, and the call sites never change. The wrapper pattern in the previous section is what makes that exit cheap — that's its real justification, not just tidiness.

Don't put these in JS-rendered surfaces. If part of the app is Inertia/React/Vue with its own icon pipeline, keep Radix-in-Blade scoped to server-rendered views. Two icon paths on one screen is the kind of inconsistency that gets caught in review, not in tests.

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.
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
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
cgv/localized-resource