Download the PHP package syriable/filament-icon-hub without Composer
On this page you can find all versions of the php package syriable/filament-icon-hub. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download syriable/filament-icon-hub
More information about syriable/filament-icon-hub
Files in syriable/filament-icon-hub
Package filament-icon-hub
Short Description A lightweight, extensible icon picker and icon provider system for Filament.
License MIT
Homepage https://github.com/syriable/filament-icon-hub
Informations about the package filament-icon-hub
Filament Icon Hub
A lightweight, extensible icon picker and icon provider system for Filament 5.
This single line gives you a searchable, paginated, keyboard-accessible icon picker covering every Blade Icons set installed in your application. Advanced applications can add local SVG directories, uploaded icons, or any remote icon API through a small provider contract, without the picker knowing where icons come from.
Contents
- Requirements
- Installation
- Basic usage
- Blade Icons
- Local SVG provider
- Custom providers
- Remote API providers
- Provider registration
- Search
- Filtering
- Caching
- Customization
- Rendering
- Icon library (uploads and hidden icons)
- Security
- Creating a provider: checklist
- Configuration reference
- Troubleshooting
- Testing
Requirements
| Version | |
|---|---|
| PHP | 8.4+ |
| Laravel | 13+ |
| Filament | 5.8.4+ |
| Livewire | 4.4+ |
Installation
filament:assets publishes the picker's small JavaScript and CSS files. Run
it again after every update of the package. It is usually part of your
composer.json post-autoload-dump scripts already.
Optionally publish the config and translations:
You do not need to register a plugin to use the field, column, or entry.
IconHubPlugin is only needed for the optional
icon library screens.
Basic usage
Form field
What gets stored
Icons from Blade Icons sets are stored by their Blade Icons name, so the value works directly anywhere Blade Icons or Filament accepts an icon:
Icons that have no Blade Icons name are stored as a namespaced
{provider}:{name} identifier: local SVG directories, the uploaded library,
and remote or custom providers.
Both formats are always accepted when reading values. Older values such as
heroicons:o-user still render and validate, and a form converts them to
heroicon-o-user when it loads. To store namespaced ids for Blade Icons too,
set blade_icons.store_as to id. A string column of 255 characters is
enough for either format.
IconPicker behaves like any Filament field: required(), disabled(),
hidden(), live(), helperText(), hint(), default(), afterStateUpdated(),
validation, dehydration, and so on.
Multiple selection stores an array, so cast the attribute to array:
Select input (compact alternative)
IconSelect is Filament's native searchable Select whose dropdown shows the
icons as a grid of tiles. The selected icon is shown with its name in the
field. Use it when a modal is more than you need, for example in dense forms,
filters, or table actions.
- It stores the same
provider:nameidentifiers asIconPickerand uses the same registry, validation, and hidden-icon rules, so the two fields are interchangeable. - Icons load when the dropdown opens and as you type. Nothing is fetched when the form renders, apart from the label of the selected icon.
- In the grid, names appear as tooltips and remain available to screen
readers. Variants that share a name are labeled, for example Star
(Outline) and Star (Solid). With
grid(false)the dropdown is a list of rows with icon, name, and variant. - Every
Selectoption still works:required(),multiple(),placeholder(),searchDebounce(),live(), and so on.
IconPicker |
IconSelect |
|
|---|---|---|
| UI | Modal with an icon grid | Dropdown with an icon grid (or a list) |
| Browsing | Infinite scroll, provider, style, and category filters | Search, first optionsLimit results |
| Best for | Visually choosing from large sets | Compact forms, when users know what they want |
Table column and infolist entry
Anywhere Filament accepts an icon
IconHub::html() returns an Htmlable, which every Filament ->icon()
method accepts:
Blade Icons
Every registered Blade Icons set is discovered automatically and becomes a provider whose ID is the set name:
| Package | Provider IDs |
|---|---|
blade-ui-kit/blade-heroicons (bundled with Filament) |
heroicons |
owenvoke/blade-fontawesome |
fontawesome-solid, fontawesome-regular, fontawesome-brands |
mallardduck/blade-lucide-icons |
lucide |
secondnetwork/blade-tabler-icons |
tabler |
codeat3/blade-phosphor-icons |
phosphor |
Install an icon package and it appears in the picker. Limit what is offered
globally in config/icon-hub.php:
Or limit it per field:
Icons in subdirectories of a set (Blade Icons names such as solid.user)
automatically get the directory as their category.
Local SVG provider
Point a provider at a directory of SVG files:
- Nested folders become categories and are part of the name.
- The directory is scanned once and the index is cached. Clear it after
adding files with
php artisan icon-hub:clear brand. - File contents are sanitized on render, and the sanitized result is cached per file and modification time.
Custom providers
A provider implements one small interface:
Providers never render HTML. They return normalized Icon objects whose
IconSource says where the artwork comes from:
| Source | Use for |
|---|---|
IconSource::blade('heroicon-o-user') |
Blade Icons names |
IconSource::svgFile('/abs/path.svg') |
Local files |
IconSource::svg('<svg …>') |
SVG markup (sanitized on render) |
IconSource::url('https://…/icon.png') |
Remote images, rendered with <img> |
When you can list every icon: extend IndexedIconProvider
This covers a JSON manifest, a design-system package, or a database table of a few thousand rows. You only build the list. Caching, search, ranking, pagination, categories, and variants are handled for you.
Anything else: implement IconProvider directly
You are responsible for search() pagination (IconQuery::$page,
::$perPage, ::offset()) and for caching expensive work through
Syriable\Filament\Plugins\IconHub\Cache\IconCache.
Remote API providers
The core ships no Flaticon, Font Awesome API, or other service-specific
code. Remote APIs extend the generic HttpIconProvider, which handles
everything that is not specific to one API:
- connect and request timeouts
- 401/403 mapped to unauthorized, 429 to rate limited (with a
Retry-Aftercool-down so the API is not hammered), 5xx to unavailable - malformed JSON and mapping errors mapped to invalid response
- search result caching per query (provider + search + category + variant + page + per page)
- priming the icon cache from search results, so rendering an icon that was picked earlier normally never calls the API
Here is a complete example for a Flaticon-style API:
Register it and it shows up in every picker:
Failure behavior
When a remote provider fails (timeout, HTTP error, bad credentials, rate
limit, malformed data), the picker shows a short provider-specific notice
and every other provider keeps working. The form never breaks. Raw
exception messages are logged through report() and never sent to the
browser.
Provider registration
There are three equivalent ways to register a provider:
Other registry operations:
A provider registered with an existing ID replaces the previous one. This lets you override a discovered provider.
Search
Search runs on the server. The browser only ever receives the current page of icons (60 by default), each with pre-rendered, sanitized markup.
- Indexed providers (Blade Icons, local, custom indexed) match every search term against the name, label, tags, and category. Exact matches rank first, then prefix matches, then the rest.
- The library provider searches with indexed database queries.
- Remote providers pass the query to the API.
Search programmatically:
With several providers, results are served provider by provider, and the cursor remembers where the previous page stopped.
Filtering
The picker builds its filters from the registered providers. Nothing is hard-coded.
- Icon set: shown when a picker offers more than one provider. Providers that are not configured are listed but disabled.
- Style (variant): shown when the selected provider exposes variants
(
ProviderMetadata::$variants). - Category: shown when the selected provider exposes categories
(
ProviderMetadata::$categories).
Caching
| Type | What | Default TTL |
|---|---|---|
index |
Enumerated icon lists (Blade Icons sets, local directories) | 1 day |
search |
Remote API result pages | 1 hour |
icon |
Remote icon lookups, primed by search results | 7 days |
metadata |
Metadata cached by custom providers | 1 day |
svg |
Sanitized local SVG contents | 1 day |
Cache keys are deterministic and include the provider and every query
parameter (search, category, variant, page, per page), so a search for
user can never return the results for home. Invalidation bumps a
generation counter and works with every cache store, including those
without tags:
In code, call app(IconCache::class)->flush('heroicons').
Customization
Arbitrary attributes
Pass any attributes (class, style, data-*, aria-*, x-*, @click,
:class) to each rendered element:
Each method accepts a closure and a merge: true argument, like Filament's
own extra*Attributes() methods.
Messages and translations
All labels and empty states (No icons found, No icons in this
collection, Provider unavailable, No providers configured) live in
lang/vendor/icon-hub/{locale}/icon-hub.php after publishing the
translations.
Styling
The UI uses Filament's own components and color variables, so it follows
your panel's theme, dark mode, and RTL automatically. Hook your own CSS into
the fi-icon-hub-* classes. For example, to change the grid density:
Rendering
- Unknown or unavailable icons render an empty string.
- Icons are decorative (
aria-hidden="true") unless you passaria-label, in which case they getrole="img". - Blade Icons render inline SVG, so
currentColorand CSS sizing work. Remote URL icons render as<img>and cannot be recolored with CSS.
Rendering never calls a remote API for icons that were selected through the picker: search results prime the icon cache, and lookups are also memoized per process. Table columns therefore stay cheap.
Icon library (uploads and hidden icons)
The optional library lets administrators:
| Action | Effect |
|---|---|
| Upload | Add an SVG icon (sanitized, stored in the database) to the library provider |
| Disable / Enable | Keep an uploaded icon but remove it from the picker |
| Delete | Permanently remove an uploaded icon |
| Hide (ignore) | Remove any icon (Font Awesome, Heroicons, remote, …) from the picker without touching its source |
| Restore | Make a hidden icon available again |
Icons that are already stored keep rendering after being hidden or disabled, so existing data never breaks.
-
Enable it:
-
Publish and run the migration (two tables:
icon_hub_iconsandicon_hub_hidden_icons): - Register the management screens on a panel:
The Icon library resource manages uploads. The Hidden icons resource lists hidden icons and offers a Hide icons action that opens a multiple icon picker.
Hide icons statically without a database:
Or programmatically:
Authorization: the resources follow Filament's normal policy
resolution. Create ManagedIconPolicy and HiddenIconPolicy (or register
policies for your own models configured in library.models) to restrict who
may upload and hide icons.
Security
| Concern | How it is handled |
|---|---|
| Malicious SVG | Every non-Blade SVG (uploads, local files, API markup) goes through an allow-list sanitizer (enshrined/svg-sanitize) that removes scripts, on* handlers, javascript: links, <foreignObject>, and remote references. Uploads are sanitized again on every render. |
| Oversized SVG | Rejected above security.max_svg_bytes before parsing. |
| Remote HTML | Providers cannot return HTML. They return an IconSource, and one central renderer produces all markup. |
| Unsafe URLs | Only https: URLs without embedded credentials render (configure security.allowed_url_schemes). javascript: and data: URLs never render. |
| SSRF | The server never fetches icon URLs. Browsers load them as images. The only outbound requests go to endpoints hard-coded in your provider class. |
| API credentials | Live in provider classes and config only. Never serialized into Livewire payloads, icon data, or error messages. |
| Browser-supplied input | Only the picker's #[ExposedLivewireMethod] methods are callable. They accept only providers allowed on that field, clamp search length and page size, and return nothing when the field is disabled. |
| Stored values | Validated server-side: format, allowed provider, and existence. |
| Attributes | Attribute names are validated and values HTML-escaped. |
| Path traversal | Local icons are resolved only through the prebuilt index, never by concatenating user input into paths. |
Creating a provider: checklist
- [ ]
id()is lowercase (a-z,0-9,.,_,-) and never changes: it is stored in your database. - [ ]
label()andstatus()do no network I/O. - [ ]
search()honorspageandperPage, and setshasMorecorrectly. - [ ]
find()resolves every name thatsearch()returns. - [ ] Icons are returned with the provider's own ID in
Icon::$provider. - [ ] Anything expensive is cached through
IconCache, or you extendIndexedIconProviderorHttpIconProvider, which do it for you. - [ ] Throw exceptions freely. The registry isolates them. Throw
ProviderException::timeout(),::unauthorized(), and so on to show a specific message. - [ ] Add
matchdefault arms when switching onSourceKind. New kinds may appear in minor releases.
Configuration reference
| Key | Default | Description |
|---|---|---|
blade_icons.enabled |
true |
Discover Blade Icons sets |
blade_icons.store_as |
name |
Store Blade Icons as their Blade Icons name (heroicon-o-user) or as id (heroicons:o-user) |
blade_icons.sets |
null |
Allow-list of set names (null = all) |
blade_icons.except |
[] |
Set names to exclude |
blade_icons.labels |
[] |
Display labels per set |
blade_icons.variants |
Heroicons prefixes | Name prefix → variant label, per set |
local |
[] |
Local SVG providers: id => [path, label?, variants?] |
providers |
[] |
Custom provider classes (container-resolved) |
hidden |
[] |
Icon IDs never offered by the picker |
library.enabled |
false |
Enables uploads and database hiding |
library.provider_id |
library |
Provider ID for uploaded icons |
library.label |
null |
Provider label (null = translated default) |
library.models.* |
package models | Swap in your own models |
library.tables.* |
icon_hub_* |
Table names |
library.navigation_group |
null |
Navigation group for the resources |
cache.enabled |
true |
Enable caching |
cache.store |
null |
Cache store (null = default) |
cache.prefix |
icon-hub |
Key prefix |
cache.ttl.* |
see Caching | TTL in seconds per type (null = forever) |
picker.providers |
null |
Default providers for pickers (null = all) |
picker.per_page |
60 |
Icons per request |
security.max_svg_bytes |
262144 |
Maximum SVG size |
security.allowed_url_schemes |
['https'] |
Allowed image URL schemes |
Troubleshooting
The picker button does nothing, or the modal is empty and unstyled.
Run php artisan filament:assets. The picker's JavaScript and CSS are
Filament assets.
My new SVG files or icon package do not appear. The index is cached. Run
php artisan icon-hub:clear, or icon-hub:clear {provider}.
A provider shows "(unavailable)" in the filter. Its status() is not
Available. For remote providers, isConfigured() usually returned
false (for example, a missing API key).
"The icon service did not respond in time." The remote API timed out.
Other providers still work. Increase $timeout on your provider, or check
the logs: every provider failure is reported through report().
A stored icon renders nothing. The provider was removed or renamed, the icon no longer exists in the source, or the provider is not available. Provider IDs are part of stored values, so never rename them. Register the old ID again if needed.
Validation says the icon is invalid. The value must be
provider:name, the provider must be allowed on that field
(->providers([...])), and the icon must exist.
Remote icons are black and cannot be recolored. URL sources render as
<img>. Return IconSource::svg($markup) from your provider if the API
offers SVG markup. It will be sanitized.
Testing
Architecture
See docs/ARCHITECTURE.md for the package structure, provider architecture, data model, rendering and caching strategies, Filament integration, security considerations, and decision records.
License
MIT. See LICENSE.md.
All versions of filament-icon-hub with dependencies
blade-ui-kit/blade-icons Version ^1.8
enshrined/svg-sanitize Version ^1.0
filament/filament Version ^5.8.4
illuminate/contracts Version ^13.0
livewire/livewire Version ^4.4
spatie/laravel-package-tools Version ^1.92