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

Nova Indicator Field Laravel Package

inspheric/nova-indicator-field

inspheric/nova-indicator-field is a Laravel Nova field for showing colored status indicators in resource tables and forms. Map values to labels and colors for quick visual status at a glance, with simple configuration and customizable states. Ideal for published, active, or approval states.

View on GitHub
Deep Wiki
Context7

Getting Started

1. Confirm compatibility before you install anything. This package's last release was January 2020 — Nova 3 / Vue 2 era. Nova 4+ replaced the field Vue API (FormField / IndexField components, Vue 3 toolchain), so a Nova 3-compiled field.js will often register nothing and render a blank cell with no PHP error. Check your Nova major first:

composer show laravel/nova
composer why-not inspheric/nova-indicator-field

2. Install and inspect the source. It's one field class and a service provider. Read vendor/inspheric/nova-indicator-field/src/ before writing code — upstream documentation is thin and the fluent setters are best confirmed from the class itself:

composer require inspheric/nova-indicator-field
ls vendor/inspheric/nova-indicator-field/src

3. Drop it into one low-risk resource. Start with a plain boolean column you already trust, on the index only:

use Inspheric\NovaIndicatorField\Indicator;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),
        Text::make('Name'),
        Indicator::make('Active')
            ->onlyOnIndex(),
    ];
}

Load the index with the browser console open. A green/red dot means you're compatible; a blank cell with no server error means the Vue component didn't register — that's an asset/version problem, not a PHP one.

First real use case: an active / published / verified boolean on a resource your support or ops team scans daily. That's the whole value proposition — one line of code turns a 0/1 cell into something readable at a glance.

Implementation Patterns

Map string states with colors and labels together. The moment you have more than a boolean, define both in one place so the dot never appears without a word next to it (color-only indicators are an accessibility gap):

Indicator::make('Status')
    ->colors([
        'draft'     => 'gray',
        'review'    => 'orange',
        'published' => 'green',
        'archived'  => 'red',
    ])
    ->labels([
        'draft'     => 'Draft',
        'review'    => 'In review',
        'published' => 'Published',
        'archived'  => 'Archived',
    ])
    ->tooltips([
        'published' => 'Visible to the public',
    ])
    ->onlyOnIndex(),

Centralize the map on the model, not in each resource. Duplicated arrays are how a new status ships unstyled six months later. Keep the state list authoritative on the model and have the field read it:

// app/Models/Post.php
public const STATUSES = [
    'draft'     => ['label' => 'Draft',     'color' => 'gray'],
    'review'    => ['label' => 'In review', 'color' => 'orange'],
    'published' => ['label' => 'Published', 'color' => 'green'],
];
// app/Nova/Fields/StatusIndicator.php
class StatusIndicator
{
    public static function make(string $attribute = 'status'): Indicator
    {
        $statuses = Post::STATUSES;

        return Indicator::make('Status', $attribute)
            ->colors(array_map(fn ($s) => $s['color'], $statuses))
            ->labels(array_map(fn ($s) => $s['label'], $statuses));
    }
}

Now every resource uses StatusIndicator::make() and a new status can't be added without a label and color.

Scoping is not optional. This field is presentational and has no input component. Always pair it with:

->onlyOnIndex()      // or ->exceptOnIndex()
->exceptOnForms()    // never render a read-only dot on a create/edit form

Use ->hideFromIndex() / ->hideFromDetail() when the same value already appears as text elsewhere.

Sorting. The field is a display wrapper — ->sortable() only works if the underlying database column is sortable and you add it explicitly. Sorting on an accessor or a joined value will throw.

Attribute vs. name. The field resolves the attribute derived from its name. If the label and the column differ (Indicator::make('Moderation state', 'moderation_state')), pass the attribute as the second argument — otherwise you get a silently empty dot.

Conditional visibility with ->canSee(fn () => $this->resource->type === 'user') keeps the field off resources where the status is meaningless.

In custom cards, metrics, or dashboards, don't force it. It's a Nova resource field; it has no place in a card's HTML. Render a badge directly there and reserve the field for index/detail rows.

Add a regression check. A tiny test that iterates your model's state constant and asserts a color exists for each key is the cheapest insurance against silent drift:

it('has a color for every post status', function () {
    foreach (array_keys(Post::STATUSES) as $status) {
        expect(Post::STATUSES[$status]['color'])->not->toBeEmpty();
    }
});

Gotchas and Tips

Blank cell → browser console, not the server log. A Nova field that fails to register produces no PHP exception. Server-side tests pass while the UI is broken. Add this to your internal runbook: "empty indicator? check console + asset registration before debugging PHP."

Pin the version and name an owner. With zero dependents and no releases since 2020, nothing upstream will tell you when this breaks. composer require inspheric/nova-indicator-field:1.* and put the field on your Nova-upgrade regression checklist the same day you adopt it. Composer wipes vendor/ edits — if you need a change, fork into an internal namespace, don't patch in place.

Key-type mismatches fail silently. $casts returning bool/int while your map keys are strings ('1' vs 1, true vs 'active') means the color lookup misses and you get an unstyled or blank dot with no warning. Cast explicitly in the model and keep map keys consistent. PHP 8+ backed enums postdate this package — pass $case->value, not the case itself.

Unmapped values render plain, with no error. A status added to the model but not to the color map degrades to something visually indistinguishable from "off." That's the failure mode that misleads an operator. The centralized-map pattern above is the mitigation; a default/fallback color is the belt-and-braces version.

Watch for N+1 on large index tables. If the indicator reads a computed accessor that touches a relationship, Nova resolves it per row. Eager-load it in the resource's indexQuery() and check query counts on your biggest table before rolling out broadly.

Dark mode is worth a look. CSS shipped in 2020 predates Nova's current theming. Verify the dot is visible in both light and dark before shipping — a dot that vanishes on dark background is worse than raw text.

Tooltips are hover-only. They're title-attribute style interactions: invisible to keyboard users and touch devices. Never put information in a tooltip that isn't also in the label.

Keep it off forms and out of customer-facing surfaces. The blast radius of a rendering regression here should be an internal admin annoyance, not an incident. If the requirement grows into click-to-filter, status transitions, or timestamps, stop extending this field and build the equivalent in-house — it's one class, and you already own the risk.

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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle