norman-huth/nova-font-awesome-field
A Laravel Nova field that adds a Font Awesome icon picker to your forms. Browse and search icons, store the selected class name, and display it in index and detail views. Easy to install and configure for any Nova resource.
Before you install anything, note the package's status: last release April 2023, archived, 3 stars, 0 dependents. Treat it as a reference implementation you may need to vendor into your app rather than a dependency you can lean on long-term. Check the src/ directory and README first — the field is small enough to read end-to-end in one sitting, and that will be faster than guessing at its API.
nova dependency must already resolve in your project):
composer require norman-huth/nova-font-awesome-field
Nova::style() in NovaServiceProvider, or a @stack/layout override.string column (e.g. icon, nullable) on the model:
use NormanHuth\NovaFontAwesomeField\FontAwesome; // verify exact namespace in src/
FontAwesome::make('Icon')
->help('Pick a Font Awesome icon')
->rules('nullable', 'string', 'max:255'),
icon column on a taxonomy/menu/category-style model, rendered in Blade as <i class="{{ $model->icon }}"></i>.The single most important mental model: the field produces a Font Awesome class string (e.g. fa-solid fa-house). Everything else — validation, rendering, search — is your responsibility.
Store the raw class, render it everywhere. The value is portable: Nova index columns, Blade views, API resources, mail templates. Keep it as one string column and never store HTML.
// app/Nova/Category.php
public function fields(Request $request)
{
return [
Text::make('Name'),
FontAwesome::make('Icon')
->nullable()
->default('fa-solid fa-star')
->hideFromIndex(),
Text::make('Icon', fn () => $this->icon
? "<i class=\"{$this->icon}\"></i>"
: '—'
)->asHtml()->onlyOnIndex(),
];
}
Restrict the picker per-resource. If the field exposes icon-set narrowing (check src/ for the setter), use a small curated list per model — a menu icon set is different from a status-badge icon set. If it doesn't expose one, wrap FontAwesome::make() in a small custom field class and hardcode the set there.
Normalise on save with a mutator so bad data never reaches the DB, regardless of whether it came from Nova, a seeder, or an importer:
protected function icon(): Attribute
{
return Attribute::set(fn ($value) => $value
? preg_replace('/[^a-z0-9\- ]/i', '', $value)
: null);
}
Pair with a icon_label / icon_color field rather than overloading one column. Colour is a separate Nova Color field; combining them into one string is the classic mistake here.
Seed and import via the class string directly. You don't need the field to write data:
Category::create(['name' => 'Home', 'icon' => 'fa-solid fa-house']);
This is why the package is thin and why you can drop it later without a data migration.
Search integration. If you use Nova search or Laravel\Scout, exclude the icon column from text search — searching fa-solid returns noise. Add a small accessor (icon_name) if you want human-searchable labels.
Reuse across Nova surfaces. The same class string works in Nova's MenuSection, tool cards, NovaSettings panels, and custom cards, provided you render it in a Vue component with the FA classes available. Keep a single Blade partial resources/views/partials/icon.blade.php and include it from both Nova and app views so the markup never drifts.
php artisan nova:field style) within a quarter. For a field this small, copying it is often cheaper than defending the dependency.fa fa-* and fas/far; FA6 uses fa-solid fa-*. The package's picker may emit one and your frontend CSS may load the other, producing invisible icons with no error. Verify by inspecting the rendered <i> class against the CSS you actually ship.nova-components asset load before touching PHP.php artisan vendor:publish --tag=... (check the README for the tag) and a npm run dev/npm run prod in the package directory if compiled assets are missing. The archived state means the shipped dist/ may be older than your Node toolchain expects.->rules(), a user (or a crafted request) can store arbitrary strings in the column, which you then echo into class="..." in Blade. Always pair the field with nullable|string|max:255 plus a mutator that strips quotes and angle brackets.{!! !!} the icon raw. Even with sanitisation, render as class="{{ $icon }}" inside a fixed <i> tag. Never render the stored value as unescaped HTML.Text column showing fa-solid fa-house is unreadable. Use the closure/asHtml pattern above, or hide the field from index entirely.component(), and point at your own Vue component — this is the cleanest way to add a searchable icon grid or restrict the set without forking the whole package.->onlyOnForms() together with a resolveUsing that overwrites the value on save.fields() plus a custom Vue component or a plain Select. Keep your icon values in a config array (config/icons.php) from day one so you're never locked in.How can I help you explore Laravel packages today?