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

tonegabes/filament-phosphor-icons

A Phosphor icon set for Filament 4 and 5 applications, exposed as a convenient enum for actions, forms, toggles, and columns. Includes weight presets, forceWeight(), and helper methods for dynamic runtime styling. Install via Composer: tonegabes/filament-phosphor-icons.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm the target major. The package is a pure-PHP enum catalogue with no service provider work, no migrations, no published assets, and no config file. Installation is one line:

composer require tonegabes/filament-phosphor-icons

Before you commit, verify two things in composer.json of the installed package: the Filament constraint (1.3.0 added Filament 5 support, 1.4.1 is current — a Filament 3 app is out of scope) and the underlying Blade Icons provider it relies on for the phosphor-* names. If the icon names resolve to blank boxes, the provider is the first thing to check, not the enum.

Verify the contract in one line. Open php artisan tinker and run:

ToneGabes\Filament\Icons\Enums\Phosphor::Star->getLabel(); // "phosphor-star"

If that returns a prefixed string, everything downstream (->icon(), ->onIcon(), @svg) will work. The enum is a BackedEnum whose value is the Blade Icons name, which is why you can pass the case directly to Filament's icon APIs.

Where to look first. Three places, in this order:

  1. vendor/tonegabes/filament-phosphor-icons/src/Enums/Phosphor.php — the actual source of truth. Grep it (grep -i "case Star" ...) rather than trusting autocomplete to be complete.
  2. phosphoricons.com — pick the visual, then look up the case name.
  3. The Filament icon docs — icon APIs are uniform across actions, forms, tables, notifications, and nav, so one page covers the rest.

First use case, scoped to an afternoon. Do not attempt a repo-wide sweep on day one. Pick one resource and change exactly three surfaces: the $navigationIcon, one table row action, and one IconColumn boolean status. That validates rendering in light and dark mode, validates the enum-to-Filament handoff, and gives you a screenshot to show before you spend the two or three days of mechanical rollout.

use ToneGabes\Filament\Icons\Enums\Phosphor;

protected static string | BackedEnum | null $navigationIcon = Phosphor::Package;

On Filament majors where $navigationIcon is still typed ?string, use Phosphor::Package->getLabel() instead. This is the single most common friction point on first install.

Implementation Patterns

Keep a semantic vocabulary class, not raw cases scattered through resources. The highest-leverage pattern is a thin app-level layer that names intent, not glyph. Design says "the theme picker uses the palette icon"; engineering changes one line and every call site follows:

namespace App\Support;

use ToneGabes\Filament\Icons\Enums\Phosphor;

final class Icon
{
    public const NAV_DASHBOARD = Phosphor::SquaresFour;
    public const NAV_USERS = Phosphor::Users;
    public const ACTION_CREATE = Phosphor::PlusCircle;
    public const ACTION_EDIT = Phosphor::PencilSimple;
    public const ACTION_DELETE = Phosphor::Trash;
    public const STATUS_ACTIVE = Phosphor::CheckCircle;
    public const STATUS_INACTIVE = Phosphor::XCircle;

    public static function emphasis(Phosphor $icon, bool $primary = false): Phosphor
    {
        return $primary ? $icon->bold() : $icon->regular();
    }
}

This is the difference between "we adopted a package" and "we adopted a convention". Without it, a future icon swap is a grep-and-replace across sixty resources.

Encode emphasis as a rule, not per-component taste. Agree on the weight convention once — primary action = bold, secondary = regular, active/selected = fill, decorative = duotone — and then enforce it through forceWeight() rather than ad-hoc case selection:

Action::make('publish')
    ->icon(Phosphor::PaperPlaneTilt->forceWeight(Weight::Bold));

Action::make('preview')
    ->icon(Phosphor::Eye->forceWeight(Weight::Regular));

The per-weight shorthands (->thin(), ->light(), ->regular(), ->fill(), ->bold(), ->duotone()) are shorter and read better at the call site:

->icon(Phosphor::StarBold->thin())

Note that every one of these returns a new enum instance. They are overrides, not mutations.

Use the shorthand's boolean form for state-driven icons. fill() accepts a boolean, which collapses the verbose match into one expression:

IconColumn::make('is_favorite')
    ->icon(fn (bool $state) => Phosphor::Heart->fill($state));

This is where the package genuinely earns its keep day-to-day: the on/off, true/false, active/inactive pairs become one-liners instead of two-branch matches across every status column in the admin.

Toggle pairs are the canonical example. Reach for onIcon/offIcon with a fill/regular pair before anything else:

Toggle::make('is_starred')
    ->onIcon(Phosphor::StarFill)
    ->offIcon(Phosphor::Star);

Drive weight from runtime state when the product allows it. forceWeight() accepts a Weight enum or a plain string, which means a user preference, a tenant setting, or a feature flag can flow straight through:

Action::make('star')->icon(Phosphor::StarBold->forceWeight($user->icon_weight));

Guard the input — an arbitrary string that does not match a case will not render — so pass the enum where you can and validate the string where you can't.

Build icon pickers from the listing helpers. If you ever need a Select that lets an admin choose an icon (custom nav items, CMS blocks, dashboard widgets), the filtered listers return label arrays ready to drop in:

Select::make('icon')
    ->options(
        collect(Phosphor::getRegularIcons())
            ->mapWithKeys(fn ($label) => [$label => $label])
            ->all()
    );

getIcons() plus getThinIcons() / getLightIcons() / getRegularIcons() / getBoldIcons() / getFilledIcons() / getDuotoneIcons() cover the weight-filtered variants. Every returned label carries the phosphor- prefix, so it is directly usable as a stored value and renderable later without transformation.

Blade surfaces use the string label, not the case. Four equivalent forms, all of which need getLabel() at the boundary:

<x-filament::badge :icon="Phosphor::Star">Star</x-filament::badge>
@svg(Phosphor::Star->getLabel())
{{ svg(Phosphor::Star->getLabel()) }}
<x-icon name="{{ Phosphor::Star->getLabel() }}" />

Keep this distinction firm: Filament component APIs accept the enum case; raw Blade directives want the string.

Treat phosphor:sync as routine maintenance, not an incident response. When Phosphor ships new icons, you are not blocked on the maintainer:

php artisan phosphor:sync --dry-run

Preview first, then either update the vendored enum or — the more durable option — point it at an enum file you own:

php artisan phosphor:sync --enum-path=src/Enums/Phosphor.php

This command is the reason a 5-star, single-maintainer dependency is defensible here: the enum is generated data, not logic. Budget a quarterly refresh, or run it when design asks for an icon you cannot find.

Gotchas and Tips

The default sync target is inside vendor/. Running php artisan phosphor:sync with no arguments writes to the package's own enum file, which composer install will overwrite on the next deploy. Always use --enum-path in anything you intend to keep, and remember that a locally-owned enum means you need to update your imports or add an aliasing layer.

Sync depends on the underlying icon set being current. phosphor:sync reads from the Blade Icons Phosphor provider, so a new upstream icon requires a composer update on that provider before syncing. If sync produces no diff, check the provider version before assuming the command failed.

Do not discard the return value of forceWeight() or the shorthands. ->fill() alone on a line does nothing; the enum is immutable and the helper returns a new case. This is easy to miss when refactoring a chained call into a multi-line one.

The README's conditional example has a type-hint mistake. The snippet declares fn (string $state) => match ($state) { true => ..., false => ... }. Use bool $state. Filament passes the column's actual state type, and a string hint on a boolean column will throw. Similarly, Phosphor::Heart->fill($state) expects a boolean — passing a truthy string will produce surprising results.

Case names encode the weight in the suffix. Phosphor::Star is regular; Phosphor::StarBold is bold; Phosphor::StarFill is fill. There is no Phosphor::StarRegular. Not every icon exists in every weight — coverage mirrors Phosphor's real catalogue — so confirm the case exists in the enum file rather than assuming symmetry.

Weight-check methods are for assertions and branching, not styling. isBold(), isFill(), isDuotone(), isLight(), isThin(), isRegular() are useful when normalising an icon that arrived from config or a database column, but reach for forceWeight() when you actually want to change the rendered glyph.

Icon-only actions still need labels. The package deliberately does nothing to force accessible text. Adopt a review rule simultaneously with adoption: any icon-only Action carries a ->tooltip() or ->label(), and no status column relies on the icon alone to convey meaning. Cheap now, expensive to retrofit across a shipped admin.

Pin the version and add one smoke test. Zero dependents and a single maintainer mean the real mitigation is your own coverage. A single test iterating your App\Support\Icon constants and asserting ->getLabel() is non-empty catches a broken or renamed case at CI time instead of in a screenshot review:

it('resolves every app icon', function () {
    foreach ((new ReflectionClass(Icon::class))->getConstants() as $case) {
        expect($case->getLabel())->toStartWith('phosphor-');
    }
});

Version coupling is the ongoing risk, and it is Filament-major-shaped. The 1.3.0 release adding Filament 5 is the pattern to expect: a lag between a Filament major and a matching package release. Pin the constraint, and make the Filament upgrade checklist include "verify icon rendering on a resource list, a form, and a notification".

The enum is large, and that is fine at runtime but noisy in the IDE. Phosphor's full catalogue is exposed; there is no curated subset. Rendered SVGs only load when used, so the runtime cost is negligible — but autocomplete on Phosphor:: is a wall of cases. The semantic constants class described above doubles as your defence against scrolling that list.

Nothing to cache or optimise. There is no config file, no service provider behaviour, and no published assets, so artisan optimize, config:cache, and deployment pipelines need no special handling. If you are hunting for a config file to tweak the prefix, there isn't one — the phosphor- prefix comes from the underlying Blade Icons set.

Exit strategy is trivial, so don't over-invest in hedging. If the package is abandoned, you vendor Phosphor.php into app/Enums/ and change one namespace; the sync command keeps that fork viable because the file is generated data. That is also the honest argument for trying it: the worst case is a copy-paste, not a migration.

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.
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table
siberfx/flysystem-wasabi
hollyit/token-replace
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel