Icons
Tagixo ships icon support through three composable sources: a built-in essentials set, auto-discovered Blade Icons packages, and custom SVG folders you register at boot. All three feed the same picker UI and are referenced by the same string ID format inside module payloads.
How auto-discovery works
Tagixo uses the Blade Icons factory mechanism. On first use, IconManager boots each registered set into a Factory instance. Discovery is lazy — sets are not loaded until the picker or a render call requests them.
To verify which sets are registered in a running instance:
php artisan tinker
>>> app(\Ccast\Tagixo\Icons\IconManager::class)->registeredSets()
The returned array lists every set key alongside its disk, path, and prefix.
Heroicons and Lucide: bundled out of the box
Both packages are declared as plugin dependencies and are available without any extra installation.
| Set | Package | Prefix | Style |
|---|---|---|---|
| Heroicons | blade-ui-kit/blade-heroicons |
heroicon- |
Stroke only (outline + solid variants) |
| Lucide | mallardduck/blade-lucide-icons |
lucide- |
Stroke only |
Note: Both bundled sets are stroke-only. If your design requires filled bullet icons (e.g. for list items), use the essentials set described below.
The essentials set
The essentials set is a small hand-curated collection of SVG icons shipped inside the plugin at resources/icons/essentials/. It exists to solve a specific gap: Heroicons and Lucide provide only stroke variants, which render poorly at small sizes as list bullets.
Included icons
| ID | Description |
|---|---|
essentials-bullet-filled |
Filled circle, used as the default list bullet |
essentials-bullet-outline |
Outline circle |
essentials-arrow-right |
Solid right arrow |
essentials-arrow-left |
Solid left arrow |
essentials-arrow-up |
Solid up arrow |
essentials-arrow-down |
Solid down arrow |
essentials-check |
Solid checkmark |
essentials-close |
Solid × mark |
essentials-external-link |
Solid external-link indicator |
Distinction from Typography rich-text lists
The essentials bullet icons are used by the IconList module as the per-item icon prop. They are not related to the <ul>/<ol> bullet styling in the Typography / rich-text (Tiptap) editor. The rich-text editor manages its own list styles through CSS; the essentials set is for explicit icon-list modules only.
Add a set by installing a package
Any Blade Icons-compatible package is automatically discovered when installed via Composer, provided Tagixo's auto-discovery is enabled (the default).
# Example: add Phosphor Icons
composer require owenvoke/blade-phosphor-icons
# Example: add Bootstrap Icons
composer require davidhsianturi/blade-bootstrap-icons
After installation, clear the icon cache:
php artisan tagixo:icons:clear-cache
php artisan optimize:clear
Popular packages
| Package | Prefix | Count | Style |
|---|---|---|---|
owenvoke/blade-phosphor-icons |
phosphor- |
7 400+ | Regular / Bold / Fill / Thin / Light / Duotone |
codeat3/blade-solar-icons |
solar- |
800+ | Linear / Bold / Broken / Outline |
davidhsianturi/blade-bootstrap-icons |
bi- |
2 000+ | Fill + Stroke variants |
jeroennoten/laravel-adminlte |
(bundles Font Awesome free) | — | Solid / Regular / Brands |
codeat3/blade-tabler-icons |
tabler- |
5 000+ | Stroke only |
andreiio/blade-remix-icon |
ri- |
2 800+ | Line / Fill |
codeat3/blade-fluentui-system-icons |
fluentui- |
1 000+ | Filled / Regular |
Register a custom SVG folder
Use IconManager::registerIconSet() in a service provider's boot() method.
Signature
IconManager::registerIconSet(
string $key, // unique set identifier, used as prefix
string $path, // absolute path to the folder
string $disk = 'local', // Laravel filesystem disk
bool $recursive = false // include sub-folders
);
Example
// AppServiceProvider::boot()
use Ccast\Tagixo\Icons\IconManager;
IconManager::registerIconSet(
key: 'brand',
path: resource_path('icons/brand'),
disk: 'local',
recursive: true,
);
SVG files in resources/icons/brand/logo.svg and resources/icons/brand/social/instagram.svg become brand-logo and brand-social-instagram respectively.
Sub-folder rules
When $recursive = true, sub-folder names are joined to the filename with -. Folder depth is unlimited, but keep paths short to avoid unwieldy IDs in the picker.
Cache flush requirement
Custom sets registered at runtime are not cached automatically. After registering a new set or adding files to an existing custom folder, run:
php artisan tagixo:icons:clear-cache
Under Octane the singleton may need a reload as well:
php artisan octane:reload
Icon IDs and how values are stored
Module payloads store the full prefixed icon ID as a plain string. There is no numeric or opaque ID — the stored value is exactly what you see in the picker.
Examples
| Picker label | Stored value |
|---|---|
| Heroicons / outline / academic-cap | heroicon-o-academic-cap |
| Heroicons / solid / academic-cap | heroicon-s-academic-cap |
| Lucide / activity | lucide-activity |
| Essentials / bullet filled | essentials-bullet-filled |
| Custom brand / logo | brand-logo |
Retrieving SVG markup from PHP
use Ccast\Tagixo\Icons\IconManager;
$svg = app(IconManager::class)->getIconSvg('heroicon-o-academic-cap');
// Returns the raw <svg>…</svg> string, or null if not found.
Variants
Variants group related icons under a logical sub-label in the picker (e.g. "outline" and "solid" appear as separate picker tabs inside Heroicons rather than as one flat list).
Defining variants in PHP
IconManager::registerIconSet(
key: 'brand',
path: resource_path('icons/brand'),
variants: [
'color' => resource_path('icons/brand/color'),
'monochrome' => resource_path('icons/brand/monochrome'),
],
);
Defining variants via config
// config/tagixo.php
'icons' => [
'sets' => [
'brand' => [
'path' => 'icons/brand',
'variants' => [
'color' => 'icons/brand/color',
'monochrome' => 'icons/brand/monochrome',
],
],
],
],
Important: variants are picker UX only
Variants do not change the stored value format. brand-logo is brand-logo regardless of which variant folder it lives in. Variants are purely a display affordance to keep the picker organised.
Using icons in custom modules
Blade @svg directive
{{-- prefix is the set key, name is the file stem --}}
@svg('heroicon-o-academic-cap', 'w-6 h-6 text-current')
{{-- essentials --}}
@svg('essentials-bullet-filled', 'w-3 h-3')
{{-- custom set --}}
@svg('brand-logo', 'h-8')
The second argument is passed as the class attribute on the rendered <svg> element.
IconManager::getIconSvg fallback
When rendering from PHP (e.g. in a PropType renderer or a form component), retrieve the SVG string directly:
$svg = app(IconManager::class)->getIconSvg($iconId, class: 'w-5 h-5');
This returns the raw SVG with the class injected onto the root element, or null if the ID is unknown.
SVG class injection
Both @svg and getIconSvg merge the class string into the SVG's existing class attribute rather than replacing it, so intrinsic SVG styles are preserved.
The icon picker UI
The picker is a searchable, lazy-loaded panel rendered inside the builder drawer when an IconPropType field is active.
Search behaviour
Typing in the search box filters across all registered sets simultaneously. Matching is case-insensitive substring on the icon ID (after prefix removal). A minimum of one character triggers the filter.
Lazy batch loading
Icons are loaded in batches, not all at once. The picker fires POST /tagixo/icons/batch with a JSON body:
{
"sets": ["heroicon", "lucide"],
"offset": 0,
"limit": 60
}
The endpoint returns an array of { id, svg } objects. The picker appends each batch to the visible grid and requests the next batch on scroll.
HTTP contract: POST /tagixo/icons/batch
| Field | Type | Description |
|---|---|---|
sets |
string[] |
Set keys to include (empty = all sets) |
offset |
int |
Pagination offset |
limit |
int |
Batch size (max 200) |
query |
string? |
Optional search string |
Response:
{
"icons": [{ "id": "heroicon-o-academic-cap", "svg": "<svg>…</svg>" }],
"total": 912,
"next_offset": 60
}
Performance considerations
| Decision | Rationale |
|---|---|
| SVG inlined at render time | Avoids per-icon HTTP requests in the frontend; saves requests at scale |
| Lazy picker batching | Prevents loading 7 000+ icons into the DOM on picker open |
| Set discovery cached | IconManager caches the set manifest per request; disk scanning happens once |
| No font-file rendering | Removes a font-load blocking dependency from the public page critical path |
Octane / Swoole singleton gotcha
Under Octane, service-container singletons survive across requests. If you register a custom set in a service provider, the set is available for the lifetime of the worker — you do not need to re-register it on each request. However, if you dynamically add SVG files to a custom folder after the worker has booted, you must reload the worker (php artisan octane:reload) for the new files to appear.
Configuration
The icons section in config/tagixo.php:
'icons' => [
'auto_discover' => env('TAGIXO_ICONS_AUTO_DISCOVER', true),
'cache' => env('TAGIXO_ICONS_CACHE', true),
'disabled_sets' => [],
'variant_schemes' => [],
],
auto_discover— whentrue, any installed Blade Icons package is registered automaticallycache— enables/disables manifest caching (setTAGIXO_ICONS_CACHE=falsein.envto disable)disabled_sets— array of set names to hide from the picker (e.g.['heroicons'])variant_schemes— map a set name to filename-prefix variants; Heroicons (o-/s-/m-/c-) is pre-configured
To flush the icon cache: app(\Ccast\Tagixo\Core\IconManager::class)->flushCache() or php artisan cache:clear.
Font-based commercial sets (Font Awesome Pro, etc.)
Font-file icon rendering (i.e. <i class="fa-solid fa-star">) is not supported by Tagixo's icon system. The builder stores SVG IDs and renders inline SVG only.
If you need Font Awesome Pro or a similar commercial font set, three options are available:
- Use a Blade Icons adapter — packages such as
owenvoke/blade-font-awesomewrap FA Free as SVG. For FA Pro you must download the SVG assets and register them as a custom SVG folder. - Export SVGs from the icon font — FA Pro's download includes individual SVG files. Place them in a custom folder and register the set.
- Use an alternative open set — Phosphor Icons (
owenvoke/blade-phosphor-icons) and Lucide cover most use cases with over 7 000 icons across fill and stroke styles.
Font-file rendering is unsupported because it requires loading an external font asset on every public page, introduces a render-blocking request, and the icon ID cannot be round-tripped as an SVG for thumbnails in the picker.
IconManager method reference
| Method | Description |
|---|---|
registerIconSet(string $name, array $config) |
Register a custom SVG icon set |
defineVariantScheme(string $setName, array $variants) |
Map filename prefixes to variant labels |
disableDefaultSet(?string $setName = null) |
Hide a specific set (or all) from the picker |
discoverFromBladeIcons() |
Trigger auto-discovery of installed Blade Icons packages |
getIconSvg(string $iconId) |
Return the raw SVG string for a given ID, or null |
getIconSvgBatch(array $iconIds) |
Return SVGs for multiple IDs in one call |
flushCache(?string $setName = null) |
Flush the icon manifest cache for one set or all |
See also
- Module system and catalog — how modules declare
IconPropTypefields - PropTypes system —
IconPropTypeschema and options - Custom form modules — using icons inside form field modules
- Tagixo plugin overview — service provider registration order