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 Pepicons Laravel Package

codeat3/blade-pepicons

Blade Pepicons brings the Pepicons icon set to Laravel Blade as simple, reusable components. Drop icons into your views with a clean tag syntax, customize size and class, and keep markup readable. No manual SVGs or icon juggling required.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require codeat3/blade-pepicons

Auto-discovery registers the service provider. No config to publish, no npm step, no @vite entry, no assets. Your first five minutes should be spent confirming what component names actually exist, because these are generated wrappers and the README won't tell you how the set's multiple styles (Pepicons ships Pop / Print / Cool flavours) are flattened into names. That convention is the thing most likely to differ from your guess:

composer show codeat3/blade-pepicons        # note the exact version, pin it
ls vendor/codeat3/blade-pepicons/src
ls vendor/codeat3/blade-pepicons/resources/views/components | head -50
# if there's no components dir, it registers with blade-icons instead:
grep -rn "registerIcon\|prefix" vendor/codeat3/blade-pepicons/src | head -20

That listing (or grep) is your icon catalog. Dump it into the repo so "is there a rocket?" is a grep -i rocket docs/icons.md instead of a browser tab:

ls vendor/codeat3/blade-pepicons/resources/views/components \
  | sed 's/\.blade\.php$//' > docs/icons.md

First use case: replace one hand-pasted <svg> in a nav or button. Attributes land on the root <svg>, so Tailwind and ARIA behave normally:

{{-- before: four lines of pasted SVG, already drifting from the design --}}
<x-pepicons-home class="size-5 text-slate-500" aria-hidden="true" />

If that renders, you're done. Everything below is polish and risk management.

Implementation Patterns

Wrap once, reference everywhere. The single highest-value pattern. Templates say <x-icon name="delete" />; the package name appears in exactly one file. When the icon set changes — or the package goes quiet — you edit a map, not two hundred Blade files.

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

@php
    $component = config('icons.map')[$name] ?? config('icons.fallback');
    $a11y = $label
        ? ['role' => 'img', 'aria-label' => $label]
        : ['aria-hidden' => 'true', 'focusable' => 'false'];
@endphp

<x-dynamic-component :component="$component" {{ $attributes->merge($a11y) }} />

/config/icons.php:

return [
    'map' => [
        'delete'   => 'pepicons-trash',
        'settings' => 'pepicons-cog',
        'empty'    => 'pepicons-print-eye',
    ],
    'fallback' => 'pepicons-question-mark',
];

Dynamic names go through the allowlist, never string interpolation. Rendering $status->icon from a model is fine via x-dynamic-component, but only after resolving through the map (or a match). A typo'd or user-derived component name throws at render time — it does not render blank. Fine in a template you authored, a 500 in a loop over DB values.

Styling. Colour should come from currentColor, which is the real reason to prefer inline SVG over an icon font: text-slate-500 hover:text-slate-900 gives you every state for free, including dark:text-slate-400. Size with size-4 / size-5 (CSS wins over the SVG's width/height presentation attributes). Set a sensible default in your wrapper and let call sites override.

Composition. Put the icon inside your <x-button> / <x-link> component and let $attributes cascade. Add shrink-0 to the icon so flex parents don't squash it:

<x-button>
    <x-icon name="delete" class="size-4 shrink-0" />
    <span>Remove</span>
</x-button>

Tests as a markup contract. Icons are not decoration in the test suite; they're the one place a version bump silently changes output:

it('renders the mapped icon for a semantic name', function () {
    $this->blade('<x-icon name="delete" />')
        ->assertSee('<svg', false)
        ->assertSee('aria-hidden="true"', false);
});

it('resolves every name in the icon map', function () {
    foreach (config('icons.map') as $component) {
        $this->blade("<x-dynamic-component :component=\"'{$component}'\" />")
             ->assertSee('<svg', false);
    }
});

That second test is your upgrade smoke test. Run it on the Laravel 13 matrix before bumping — 1.7.0's changelog line is a claim, not evidence you can inspect.

Rollout and exit hatch. Convert one surface per PR (nav first, then empty states), and track adoption in CI with grep -r "pepicons-" resources/views. Pin the exact version. Snapshot the handful of SVGs you actually use into resources/svg/ and have your wrapper's map point there if the package ever stalls — no call site changes.

Deploy ordering. If the package registers icons with blade-icons rather than shipping Blade files, add php artisan icons:cache before php artisan view:cache in your deploy script, and icons:clear locally after any package upgrade or you'll chase phantom "icon not found" errors.

Gotchas and Tips

Inline SVG does not survive HTML email. Gmail and Outlook desktop strip <svg>. If a transactional mail needs an icon, export a PNG or use a text/CSS shape. "Server-rendered SVG" is not a guarantee about the client.

Attribute merge order is load-bearing. {{ $attributes->merge(['class' => 'size-5']) }} puts caller classes after the defaults so <x-icon name="x" class="size-8" /> wins. Reverse it in the wrapper and every override silently loses — maddening to debug because the markup looks correct.

Audit currentColor per icon, not per set. Pepicons mixes fill-based and stroke-based glyphs across styles. If the generated SVG hardcodes fill="#000", text-* colour and hover transitions will look broken next to siblings that inherit. Check the dozen icons in your design system, not the whole catalog. Also watch style="width:24px" inline — that beats your Tailwind classes where a presentation attribute wouldn't.

Accessibility is two lines, and they're different lines. Decorative: aria-hidden="true" focusable="false". Meaningful: role="img" plus aria-label — an aria-label on an <svg> without role="img" is unreliably announced. Don't rely on the package to guess which case you're in; make your wrapper require it.

Missing icons fail loudly, so route dynamic input through the map. Covered above, but it's the difference between a fallback glyph and a 500 on a page a user triggered.

Prefix collisions and clean single-icon overrides. If another icon package is installed, check the prefixes don't collide (php artisan about won't help; grep the service providers). Laravel resolves your application's components before the package's — so resources/views/components/pepicons/home.blade.php wins over the vendor copy without touching vendor/. That's also the escape route if one glyph needs fixing.

"Component doesn't exist" after install: composer dump-autoload, then php artisan view:clear. Never edit anything under vendor/ — overrides live in resources/views/components/.

Watch the transitive chain on a Laravel major, not the wrapper. Run composer why blade-icons before upgrading; if this package sits on blade-icons, that's the real breakage vector. Confirm the resolved blade-icons version against Laravel 13 in CI rather than trusting the thin wrapper's own constraint.

Payload sanity check, with data. Roughly 0.5–2 KB of markup per icon. Ten icons in a nav is nothing; a 40-icon dashboard is ~40 KB pre-gzip. Open one heavy page with the network panel before deciding to sprite anything — and then sprite only the icons repeating 20+ times on that view.

Tailwind purging is fine, concatenation isn't. Icon classes come from your templates so they're detected — but "text-{$color}-500" is invisible to the scanner. Keep colour decisions at the call site or safelist them.

Two integration shapes to be aware of. Inertia/Vue pages can't use Blade components — use the pepicons npm package there and keep the wrapper's map as the parity document. Livewire is fine, but a dynamic component name computed in a Livewire re-render is still a render-time throw if the value is bad.

Maintenance posture. Zero stars, zero dependents, one maintainer. That doesn't disqualify it — MIT, presentation-only, no runtime calls, no data or auth surface — but it does mean: pin the exact version, keep the SVG snapshot fallback, and put a twelve-month or next-Laravel-major review on the calendar rather than assuming someone else will notice.

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