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

codeat3/blade-solar-icons

Blade components for the Solar icon set, letting Laravel developers drop crisp SVG icons into views with simple x-solar tags. Multiple styles and weights, no build step or extra tooling required.

View on GitHub
Deep Wiki
Context7

Getting Started

Install. One Composer line, no publish step required:

composer require codeat3/blade-solar-icons

Service-provider auto-discovery registers every icon as a Blade component built on blade-ui-kits/blade-icons. Confirm what you actually resolved before writing templates:

composer show codeat3/blade-solar-icons blade-ui-kits/blade-icons

The component API is identical on 1.3.1 (Laravel 11/12) and 1.4.1 (Laravel 13), so the resolved version does not change how you call it.

Where to look first. Don't read the package source — read the component inventory. Icons live as SVGs inside the vendor tree, organised by style:

ls vendor/codeat3/blade-solar-icons/resources/svg
find vendor/codeat3/blade-solar-icons/resources/svg -name '*home*'

That directory listing is your icon picker. Names map to tags by kebab-casing: home-2-bold.svg → <x-solar-home-2-bold />.

Naming convention. <x-solar-{icon-name}-{style} /> where style is one of linear, bold, outline, broken, bold-duotone, linear-duotone:

<x-solar-home-linear class="w-6 h-6 text-blue-500" />
<x-solar-user-bold class="w-6 h-6 text-slate-700" />
<x-solar-settings-bold-duotone class="w-5 h-5 text-indigo-600" />

First use case. Replace the copy-pasted <svg> blob in your layout partial. Take an icon you already ship, delete the markup, and drop in the component tag; attributes pass straight through, so existing Tailwind classes keep working:

{{-- before: 30 lines of inline SVG --}}
{{-- after: --}}
<x-solar-magnifier-linear class="w-4 h-4 stroke-2 text-gray-400" />

Verify in the browser, then check the emitted HTML is a single <svg> with your classes merged on.

Implementation Patterns

Wrap it immediately. The single most valuable ten lines you will write. Every call site goes through your own component so the vendor name never appears in feature templates:

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

<x-dynamic-component
    :component="'solar-' . $name . '-' . $style"
    {{ $attributes->merge(['class' => 'w-5 h-5 shrink-0', 'aria-hidden' => 'true']) }}
/>

Usage stays ergonomic:

<x-icon name="home" class="text-blue-500" />
<x-icon name="trash" style="bold" class="text-red-600" />

This gives you one place to change default size, add aria-hidden, swap the source later, and validate names.

Data-driven icons need an allowlist. The wrapper above resolves a component name at runtime, and blade-icons throws Unable to locate a class or view for component for anything unknown. Never pass a database or request value in unvalidated:

// app/Support/Icon.php
final class Icon
{
    public const ALLOWED = ['home', 'user', 'settings', 'bell', 'trash'];

    public static function safe(?string $name, string $fallback = 'home'): string
    {
        return in_array($name, self::ALLOWED, true) ? $name : $fallback;
    }
}

Then guard at the boundary — in a controller, a view model, or an enum cast — and keep the check out of the template.

Two components, two intents. Decorative icons and meaningful icons are different accessibility contracts. Keep the default decorative (aria-hidden="true"), and add a second variant for icons that are the label:

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

<x-dynamic-component
    :component="'solar-' . $name . '-' . $style"
    role="img"
    :aria-label="$label"
    {{ $attributes->merge(['class' => 'w-5 h-5 shrink-0']) }}
/>
<x-icon name="trash" />
<x-icon-label name="warning" label="Requires attention" class="text-amber-500" />

Style as a design-system decision, not a per-template choice. Pick one style for body UI (typically linear) and one for emphasis/navigation (bold), then set them as the wrapper default and a named variant. Templates should rarely name a style directly — otherwise you get four styles on one page and a design review you can't pass.

Sizing scale through the wrapper. Don't sprinkle arbitrary w-4 h-4 / w-5 h-5 / w-6 h-6 across templates. Add a size prop mapped to a fixed set of literal classes:

@php
    $sizeClass = match($size ?? 'md') {
        'sm' => 'w-4 h-4',
        'lg' => 'w-6 h-6',
        'xl' => 'w-8 h-8',
        default => 'w-5 h-5',
    };
@endphp

This also keeps Tailwind's scanner happy — see Gotchas.

Colour via currentColor, not hardcoded fills. Solar's linear/broken icons are stroke-based and inherit currentColor; bold/duotone are fill-based. text-* classes work for both, so drive colour from the parent:

<a href="#" class="group flex items-center gap-2 text-slate-600 hover:text-indigo-600">
    <x-icon name="settings" class="group-hover:rotate-90 transition" />
    <span>Settings</span>
</a>

For dark mode, set colour once on a container and let icons inherit — no per-icon dark: variants.

Non-browser rendering. This is where the package earns its keep. Inline SVG renders in mailables, PDF views (DomPDF/Snappy), error pages, and CLI-generated HTML with no asset pipeline:

{{-- resources/views/vendor/mail/html/button.blade.php or a receipt partial --}}
<x-icon name="check-circle" style="bold" class="w-4 h-4 text-emerald-600" />

Caveats: email clients strip <style> and external CSS, so prefer explicit style="" attributes or presentation attributes for anything critical in mailables, and keep icons simple (linear reads better at small sizes than bold-duotone).

Performance on icon-dense pages. blade-icons discovers components by scanning directories; with ~7,400 icons that is per-request filesystem work when uncached. Add to your deploy pipeline:

php artisan icons:cache

and clear it on rollback (php artisan icons:clear). Verify it in staging — a cached-vs-uncached discrepancy shows up as a Component not found exception only on the deploy that added an icon.

If a single view renders dozens of the same icon in a loop (a table row action, for instance), the inline SVG is duplicated per row. For that specific case, extract a one-off local partial with the SVG in a <symbol> and reference it with <use>, rather than fighting the package.

Livewire / Inertia. Works unchanged — components render server-side. In Livewire, keep <x-icon> inside your Blade views, not inside wire:-bound attributes; if you need to swap an icon reactively, swap the name prop on the wrapper, not the tag itself.

Testing. Functional tests are weak here because the output is markup. Assert on presence and accessibility attributes rather than SVG internals:

$this->get('/dashboard')
    ->assertSee('solar-home-linear', false)
    ->assertSee('aria-hidden="true"', false);

Better: a single test that iterates Icon::ALLOWED and renders each through the wrapper, so an upstream rename fails the build instead of a production route.

Aliasing / defaults. If the package publishes a config file, that is where you set default attributes and aliases — but prefer the wrapper for anything you own. Reserve the config for cross-cutting concerns you want applied even if someone bypasses the wrapper. Publish and inspect it before relying on the key names:

php artisan vendor:publish --provider="Codeat3\BladeSolarIcons\BladeSolarIconsServiceProvider"

Gotchas and Tips

Tailwind will not generate classes built at runtime. class="w-{{ $size }} h-{{ $size }}" produces nothing in the compiled CSS. Always map to full literal class strings ('w-4 h-4') inside a match/array in the wrapper — the scanner only sees literals in source.

A missing or renamed icon is a runtime exception, not a build failure. Component not found fires at render, on whatever route happens to use it. This is the worst possible shape for a cosmetic dependency. Mitigations: the allowlist above, a render test over every icon name your app uses, and pinning the version in composer.json ("codeat3/blade-solar-icons": "1.4.1" or a caret you actually watch).

The release line skips 1.3.1 → 1.4.1 with no 1.4.0. Before pinning, check tags and the CHANGELOG directly, and run a dry-run resolution against your real lockfile to see what moves transitively:

composer update codeat3/blade-solar-icons --with-dependencies --dry-run

Watch blade-ui-kits/blade-icons and the illuminate/* floor. The real compatibility surface is those, not this package's handful of files. Then render ~20 icons that actually appear in production and diff the SVG — regeneration is silent and passes functional tests.

The bare <x-solar-home /> form resolves to a default style. Don't rely on it in application code; be explicit (style="linear") or route everything through your wrapper. Ambiguity here is how you end up with mismatched styles across a page after an upgrade.

$attributes->merge() order matters. In the wrapper, merge(['class' => 'w-5 h-5', ...]) means call-site classes are appended, so class="w-10 h-10" produces both w-5 h-5 w-10 h-10 — the last one wins in CSS, but you get confusing markup and unpredictable results with conflicting utilities. Either document that overrides are additive, or don't set a default size in the wrapper and let call sites own it.

Don't forget to spread attributes. Writing {{ $attributes }} (rather than :attributes) on the dynamic component is the usual bug — the icon renders but class, id, and wire: bindings vanish. Same for $attributes->merge(): forgetting merge means your aria-hidden default disappears whenever a caller passes any attribute.

Stroke and fill overrides behave differently per style. stroke-2 only affects linear/broken; on bold/duotone the shapes are filled and stroke tweaks do nothing or produce ugly artefacts. If you expose a stroke prop on the wrapper, gate it on the style.

Attribute values are escaped; the SVG is not. You cannot pass raw markup as an attribute and expect it to render. If you need a <title> inside the icon, publish/override the component view rather than trying to inject it.

icons:cache is a deploy artefact, not a runtime cache. Forgetting it in production silently degrades every request; forgetting icons:clear on a rollback silently keeps serving the previous icon set. Wire both into your deploy and rollback scripts, and treat a stale cached icon as a "check the cache" debugging step first.

Debugging checklist when an icon won't render.

  1. find vendor/codeat3/blade-solar-icons/resources/svg -name '*{name}*' — does the file exist, and with which style suffix?
  2. Is the cache stale? php artisan icons:clear.
  3. Are you using <x-dynamic-component> with a name your allowlist rejected?
  4. Check the actual component registered: php artisan tinker → collect(app('blade-icons')->getManifest() ?? []).

Extension points, in order of preference. (1) Your wrapper component — covers ~95% of needs. (2) A local Blade component with hand-written SVG for the few bespoke/brand icons you cannot get from Solar. (3) The package config for global aliases/defaults. Avoid editing files under vendor/ or relying on unpublished internal view paths — both break on the next composer update.

Don't adopt dev-master while troubleshooting. The obvious fix for a missing icon is to bump the constraint; the actual risk is pulling an unreviewed regenerated icon set into a release. Pin, and if you need a specific icon, upgrade deliberately with a render diff.

Where this package is the wrong tool. A JS SPA should use an npm icon package; running both pipelines is pure overhead. A page with hundreds of icons should use a sprite with <use>, not hundreds of inline <svg> blocks. And if your app uses fewer than ~20 icons, a local component with three hand-copied SVGs is simpler and has no upgrade surface at all.

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.
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
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect