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

codeat3/blade-jam-icons

A Laravel Blade package that brings Jam Icons to your views as simple, reusable components. Render any icon with a clean Blade tag, customize size and class, and keep your markup readable without copying raw SVG by hand.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and render.

composer require codeat3/blade-jam-icons

The service provider is auto-discovered. There is no registration, no facade, no publish step required to get started. Every Jam glyph is a Blade component named jam- plus the kebab-case icon name:

<x-jam-home />
<x-jam-alarm-clock class="w-4 h-4 text-gray-500" />

That is the entire API. Everything below is about where you put those two lines.

Where to look first, in order:

  1. vendor/codeat3/blade-jam-icons/resources/svg/ — the authoritative icon list. Filename minus .svg is the component suffix. Dump it once into a scratch file (ls ... | sed 's/.svg//') on day one rather than guessing names.
  2. vendor/codeat3/blade-jam-icons/config/blade-jam-icons.php — defaults for class, attributes, fallback, prefix.
  3. blade-ui-kit/blade-icons — the actual engine. When attribute behaviour, fallbacks, or resolution surprises you, the answer lives in that package's docs, not in the Jam wrapper.

First real use case — swap one hardcoded SVG. Find a layout or nav partial with an inline <svg> blob (or an <i class="jam jam-*"> if you're coming from the icon-font build), replace it with <x-jam-... class="...">, run php artisan view:clear, and confirm the glyph inherits currentColor from its text-colored parent. Jam is stroke-based, so text-blue-600 drives the color; fill-blue-600 does nothing. Once that single swap renders identically, the migration is mechanical and you can stop reading docs and start reading the vendor SVG directory.

Do this before icon number two: publish the config and commit it.

php artisan vendor:publish --tag=blade-jam-icons-config

House defaults (size, aria-hidden, focusable="false") belong in a tracked file in your repo, not repeated in views.

Implementation Patterns

Static usage inside existing markup. The component is a drop-in <svg>; all attributes pass through to the root element, so Tailwind works untouched:

<button class="flex items-center gap-2 text-blue-600 hover:text-blue-700">
    <x-jam-save class="w-5 h-5" />
    Save
</button>

Dynamic icons from data — the pattern that pays for the package. Nav config arrays, menu tables, status maps, CMS-driven dashboards:

<x-dynamic-component :component="'jam-' . $item->icon" class="w-4 h-4 shrink-0" />

This collapses "designer exports SVG → dev pastes markup" out of every sprint that touches admin tables or configurable navigation. It is also where the only real risk lives (see Gotchas).

Wrap it on day one. One file becomes the only place the package is named:

{{-- resources/views/components/icon.blade.php --}}
@props(['name', 'size' => 'w-5 h-5'])
<x-dynamic-component
    :component="'jam-' . $name"
    {{ $attributes->merge(['class' => $size]) }}
    aria-hidden="true"
/>

Call sites read <x-icon name="search" />. A future swap to Heroicons or a design-system set becomes a single-file diff instead of a codebase hunt. This is the one design commitment worth enforcing in review.

Compose upward, not outward. Icon+label buttons, badges, alerts, empty states are the natural unit — build them as components that consume <x-icon>, so sizing and spacing decisions stay in one layer:

@props(['icon', 'label'])
<a {{ $attributes->merge(['class' => 'flex items-center gap-2 px-3 py-2 rounded']) }}>
    <x-icon :name="$icon" size="w-4 h-4" />
    <span>{{ $label }}</span>
</a>

Config defaults for the truly global stuff only. Bake aria-hidden, focusable="false" and a base size into the published config; keep color, margin and size variants in the wrapper. Config applies to every icon in the app — it's a blunt instrument, and per-instance concerns get lost in it.

Livewire. Icons are server-rendered markup with no JS, so they work unmodified in Livewire views, inside loops, and after re-renders. Drive the name off public state: $sortDirection === 'asc' ? 'chevron-up' : 'chevron-down'.

Testing. Assert on rendered output, not view source:

$this->blade('<x-jam-alarm-clock />')->assertSee('<svg', false);

Then add the high-value one: a data-driven test that loops over every icon value actually present in your database/config and renders <x-icon :name="$value" />. Static names are caught at compile time; dynamic strings are not, and this test is the only thing standing between a bad row and a 500 in production.

Gotchas and Tips

Unknown dynamic names fail at render time, in production, as a 500. 'jam-' . $row->icon has no build-time safety net. Two mitigations, use both: set a fallback icon in config so a bad value degrades to a generic glyph instead of throwing, and generate an allowlist from the vendor SVG directory (a config constant or enum) so dynamic names can be validated before they reach the template.

Class merging does not happen on the vendor component. class passes straight through — it does not merge with the config value. Pass class="w-5 h-5" while config sets w-6 h-6 and you get both in the attribute; CSS source order decides the winner, not your intent. Keep sizing in exactly one place: the wrapper.

Cache invalidation is the #1 false alarm. After editing the published config: php artisan config:clear (or config:cache). After editing your wrapper component: php artisan view:clear. "My class isn't applying" is almost always a stale compiled view in dev.

Published config is yours forever. Composer won't update it. Re-diff against the vendor stub when you bump versions, or you'll silently miss new keys.

Inline SVG costs payload, not CPU. Each icon inlines its full <svg> markup. Fine at normal density; measure icon-per-row admin tables and icon-heavy dashboards before optimizing — gzip/brotli largely neutralises the repetition. If a specific view is genuinely heavy, that view gets a sprite or cached partial, not the whole app.

jam-* is a global Blade component namespace. If you own a component literally named jam-something, or you're stacking several codeat3/blade-* packs, check the prefix config before debugging phantom resolution errors.

Don't put these in emails or non-Blade renderers. Inline SVG support in mail clients is unreliable; for mailables, render a PNG or link out.

Accessibility is opt-out, not opt-in. Baking aria-hidden="true" into <x-icon> handles decorative icons; icon-only buttons still need aria-label on the interactive element or sr-only text. Make that a review rule rather than a per-page decision.

Extension points are thin — lean on the wrapper, not vendor patches. There's no per-icon override mechanism worth fighting for. Custom glyphs, size scales, or variants go in your own <x-icon> component (a match on name, a $sizes map). Never edit vendor/. And keep the escape hatch in mind: the SVGs are static files, so vendoring or forking them internally is an hours-scale task if the package ever stalls.

Resolution conflicts are the real install risk. This wrapper pulls blade-ui-kit/blade-icons and illuminate/support. In an app that already has icon packs, run composer update --dry-run against each lockfile before committing. Version 1.8.0 is a Laravel 13 compatibility release — no new icons, no API change — so pin ^1.8 and confirm whether the constraint widens (one version across the estate) or replaces older majors (a deliberate two-tier estate).

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource