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

Filament Icon Picker Laravel Package

guava/filament-icon-picker

Filament Icon Picker adds an icon picker form field and matching table column to Filament panels. Choose from any installed blade-icons kit, Heroicons included by default—ideal for custom navigation, model, and frontend icons. Token-secured endpoints, configurable caching.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire up (3 commands + 1 CSS line):

composer require guava/filament-icon-picker
php artisan filament:assets
php artisan vendor:publish --tag=filament-icon-picker-config   # optional, but do it early

Because the field ships its own Blade/Tailwind classes, you must have a custom Filament theme and add the package's views to the Tailwind content scan (theme.css, Tailwind v4 syntax):

@source '../../../../vendor/guava/filament-icon-picker/resources/**/*';

Skipping this is the single most common "the picker renders as an unstyled list of letters" failure — the icons exist, the CSS doesn't.

First use case — a model gets a customizable icon:

use Guava\IconPicker\Forms\Components\IconPicker;

IconPicker::make('icon')
    ->label('Icon');
// Careful: NOT Filament\Tables\Columns\IconColumn
use Guava\IconPicker\Tables\Columns\IconColumn;

IconColumn::make('icon');

Store it as a plain string column ($table->string('icon')->nullable()), cast nothing special, and render it on the frontend through your blade-icons kit as usual.

Where to look first, in order:

  1. The version compatibility table — Filament 3 → 2.x, Filament 4 → 3.x, Filament 5 → 4.x/5.x. Getting this wrong produces confusing Livewire/asset errors rather than a clean composer conflict.
  2. The published config file config/filament-icon-picker.php (route prefix, middleware, cache settings) — this tells you more about runtime behaviour than the README.
  3. The hosted docs at guava.cz for scopes, set limiting, uploads, and the search-result view.
  4. IconScope — this is the identity model behind "custom/uploaded" vs. "kit" icons, and understanding it makes the rest of the API predictable.

Implementation Patterns

Resource form + table, the bread-and-butter pattern. One field, one column, no extra plumbing:

public static function form(Schema $schema): Schema
{
    return $schema->components([
        IconPicker::make('icon')
            ->required(),
    ]);
}

public static function table(Table $table): Table
{
    return $table->columns([
        IconColumn::make('icon')->label(''),
        TextColumn::make('name'),
    ]);
}

Restricting the icon universe per field. The package supports limiting which icon sets appear, and 5.x enforces both the scope and the allowed sets when resolving an icon server-side. Use this aggressively — a full Heroicons + Font Awesome + Phosphor palette is thousands of SVGs and a bad UX in a dropdown-sized modal. Expose the two or three sets that match your design system rather than "everything installed."

Scopes for multi-tenant / per-record palettes. Since 3.x the package has a scope concept, and 5.x centralised custom-icon scope ids in IconScope. The day-to-day pattern is: a global settings page gets the full kit; a tenant-facing "branding" panel gets a narrowed set; user-uploaded icons live in a separate scope so one tenant can't see another's uploads. If you're building anything multi-tenant, wire the scope deliberately in the form schema rather than relying on defaults.

User-uploaded icons. The package supports letting users upload their own SVGs (incoming SVGs are sanitized and labels are restricted in 5.x). Treat this as a feature flag: it's great for "let the client pick their own nav icon," and it's a moderation surface. Pair it with ->acceptedFileTypes(...)-style Filament upload validation on the underlying field and a disk you control.

Reuse the stored value for navigation & frontend. The stored value is a bare icon id (labels are cosmetic and, since 5.x, no longer carry the set prefix — "academic cap", not "Heroicon o academic cap"). That means you can safely pipe the column into:

// Panel navigation built from DB-driven settings
$navigationItems = Setting::pluck('icon', 'label');

and on the frontend <x-icon :name="$model->icon" /> with blade-icons. Keep a ?-> guard — see gotchas.

Cache deliberately. 5.x caches icon listings server-side; config lives under filament-icon-picker.cache.*. For a panel with a handful of users, the defaults are fine. For a large tenant base, check whether the cache should be per-scope and flush it whenever you deploy a new icon set — a stale listing shows an icon picker that's missing the icon you just shipped.

Integration tip: wrap it in a shared concern. If icon choice shows up on Page, Post, Category, and Tenant, don't repeat the field config six times. Extract a HasIconField trait / helper that returns a pre-configured IconPicker with your standard allowed sets and label, then call ->modifyUsing() / override per resource.

Don't forget search-result views. The README explicitly calls out "search result views" as a documented integration point — if you implement global search, the icon column needs the matching Guava column (or the correct rendering path) to appear in results.

Gotchas and Tips

Import collision with Filament's own IconColumn. Filament ships Filament\Tables\Columns\IconColumn. The Guava one is a different class with different behaviour (it resolves and renders the stored icon id). IDE auto-import will happily pick the wrong one and you'll get a boolean-style icon column with no error. Alias it if you use both:

use Guava\IconPicker\Tables\Columns\IconColumn as GuavaIconColumn;

Two registered routes exist and they matter. /_icon-picker/index and /_icon-picker/svgs, both secured by an encrypted per-field token. Practical consequences:

  • If you front the app with a strict CSP or a proxy that strips query strings, the SVGs stop loading.
  • If you set a global route middleware group that requires auth, verify the picker still works — the token is the authorization, but the middleware stack still runs.
  • The route prefix and middleware are exactly what the published config file is for; change them if _icon-picker collides or your infra whitelists URL paths.

Never render a stored icon without a null check. In 5.x getIcon() returns null for ids with no matching file. This is deliberate (an icon set was removed, or a tenant was deleted) — but it means your Blade template must survive null. $model->icon?->... or @if($model->icon).

Upgrading 4.x → 5.x is not cosmetic. The breaking changes are real and silent-ish:

  • fuse.js → @leeoniya/ufuzzy (client-side search behaviour and relevance ordering change).
  • getSetJs(), getIconsJs(), getIconSvgJs() are removed — anything you wrote against those (custom Livewire views, custom pickers) breaks.
  • CanBeCacheable is removed, and cache config moved from icon-picker.cache.* to filament-icon-picker.cache.*. A copied-over old config file will simply be ignored — the picker looks uncached and you won't see an error.
  • Icon labels dropped the set prefix. If you display the label anywhere (audit logs, exports, "you selected: Heroicon o academic cap"), that string changes.

Read the upgrade guide before bumping; pin 3.x on Filament 4 rather than assuming forward compatibility.

php artisan filament:assets is not a one-time step. Run it after every composer update of this package and after publishing config. Most "picker looks broken after deploy" reports are a missed asset publish or a stale theme build.

Rebuild your theme after upgrading the package. The @source glob picks up new/changed classes, but Tailwind only rescans on build. A CI pipeline that caches public/css/filament/* will serve stale CSS.

Performance: the icon list is the bottleneck, not the picker. 5.x added batching of SVG fetches and server-side listing cache, and it now resolves single icons by file lookup instead of enumerating the whole set. That last one matters for table columns: rendering 50 rows with an icon column no longer lists 5,000 SVGs. If you're on 4.x, that's a strong reason to move to 5.x.

Debugging checklist, in order: (1) custom theme exists and has @source? (2) filament:assets run? (3) correct Guava IconColumn import? (4) config published and namespace filament-icon-picker.*? (5) route prefix reachable / not blocked? (6) getIcon() returning null because the set prefix changed on upgrade?

Extension points worth knowing. The config file (routes/cache/middleware) is the primary one. Beyond that, the documented surface for scopes, allowed sets, and custom icon uploads is where you customise behaviour — the package deliberately removed the JS-accessor methods in 5.x, so treat the server-side config + schema configuration as the extension path and avoid reaching into internals.

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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin