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 Tooltip Field Laravel Package

philperusse/nova-tooltip-field

A Laravel Nova field that adds tooltip support to your resources, letting you show helpful hints and contextual information on hover. Keep forms and detail views clean while giving users quick, customizable guidance exactly where they need it.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you install anything, check your Nova version. This field was published once, on 2018-11-14, against the Nova 1.x generation. If production is Nova 3 or later (Vue 3 / Tailwind era), stop here — use Nova's native ->help('...') on the field itself. It is one method call, it is accessible, and it is maintained by the vendor. Everything below assumes you are on a legacy Nova 1.x/2.x panel with no near-term upgrade, which is the only environment where this package has a realistic chance of rendering.

Minimal steps for that case:

composer require philperusse/nova-tooltip-field:^1.0

Pin the constraint explicitly — do not float * on a package with a single release and no maintainer.

Where to look first, in this order:

  1. composer.json in the package — the laravel/nova and illuminate/* constraints tell you immediately whether Composer will even resolve against your install. This is the go/no-go gate.
  2. src/ — the whole package is a Field subclass (likely Philperusse\NovaTooltipField\Tooltip; confirm the exact class name on disk, there is no reliable README-level API contract).
  3. dist/ or resources/js/ — determine whether a compiled bundle is shipped or whether you must build from source. This is the fork-vs-reimplement decision point. If only a compiled blob exists with no recoverable build step, you cannot upgrade it later.

First use case. Pick exactly one field on one Resource where a misconfiguration actually costs money or a support ticket — a billing rule, a status transition, a regional setting, a deprecated flag. Add the tooltip there and nowhere else. Verify it renders in a sandbox at exact production parity (same Nova major, Laravel, PHP, Node) before it touches a shared environment.

A working shape, hedged because the exact fluent API must be read from src/:

use Philperusse\NovaTooltipField\Tooltip;

public function fields(Request $request)
{
    return [
        Tooltip::make('Billing Rule')
            ->text('Hourly plans are prorated on downgrade; flat plans are not.')
            ->onlyOnForms(),

        Select::make('Billing Rule', 'billing_rule')->options([...]),
    ];
}

Place the tooltip immediately before the field it explains. Adjacent placement is the entire value proposition; a tooltip three fields away is noise.

Implementation Patterns

Treat the field as meta, never as data. A tooltip carries no state, but Nova will still attempt to fill it on save. Give it an attribute that is not a model column and explicitly no-op the write:

Tooltip::make('Billing Rule')
    ->text(__('admin.hints.billing_rule'))
    ->onlyOnForms()
    ->fillUsing(fn () => null),

Without the fillUsing no-op you get an SQL error on update or a silent mass-assignment surprise. This is the single most common way this field breaks a working form.

Keep copy in lang files from day one. The widget itself will not localise, but your strings can, and — more importantly — when you eventually migrate to native ->help(), the migration becomes mechanical: one __() key per field, swapped at the call site. If you hardcode English strings into fields(), the upgrade becomes an archaeology exercise.

Wrap it in your own factory. Do not scatter vendor calls through every Resource. Define a thin helper so the dependency appears in exactly one file:

class Hint
{
    public static function make(string $key): Tooltip
    {
        return Tooltip::make(__("admin.hints.{$key}.label"))
            ->text(__("admin.hints.{$key}.text"))
            ->onlyOnForms()
            ->fillUsing(fn () => null);
    }
}

Now Hint::make('billing_rule') is the only thing Resources know about. When you fork or replace the package, exactly one class changes.

View scoping. ->onlyOnForms() is the default posture. ->onlyOnDetail() is defensible for read-only audit screens where an operator needs context on a historical record. Do not use it on index — Nova index tables are already cramped, and a hover-only affordance in a dense table is undiscoverable and untappable.

Group with Panels, not with tooltips. If a section needs three hints, that is a signal the section needs a Panel with a short description at the top rather than three separate hover widgets. Use tooltips for the one or two genuinely surprising inputs inside an otherwise self-explanatory panel.

Testing. The tooltip is client-side; PHP tests can only assert that the field appears in fields() and that its meta carries the expected copy. Add that assertion — it is cheap and catches accidental deletions during refactors:

it('exposes the billing rule hint', function () {
    $fields = (new Invoice)->fields(Request::create('/'));
    expect(collect($fields)->firstWhere('attribute', 'Billing Rule')->meta)
        ->toMatchArray(['tooltip' => __('admin.hints.billing_rule.text')]);
});

For the hover behaviour itself, a Dusk smoke test or manual QA checklist is the pragmatic ceiling. Do not invest in browser automation for an unmaintained widget.

Gotchas and Tips

It fails silently. After a Nova upgrade, this field is far more likely to render blank, unstyled, or as a stray input than to throw an exception. Nobody gets paged; a support agent just misconfigures a record six weeks later. Add a manual post-upgrade checklist item: open each Resource that uses a hint and confirm the icon appears. There is no runtime signal to rely on.

Hover-only is an accessibility failure, not a polish gap. The widget cannot be reached by keyboard and is unreadable to screen readers; on tablets there is no hover at all. If internal tooling has any accessibility obligation — or if your ops team uses iPads — this is a compliance question. Native ->help() renders inline text that is keyboard-reachable and announced by assistive tech. If you fork, add tabindex="0" and aria-label to the trigger and consider a click-to-toggle fallback for touch.

Check how the asset is registered. Some Nova field packages register their script in the field's boot() or a service provider; others require php artisan nova:publish. If the tooltip renders as nothing but the surrounding form is fine, open the browser console and look for [Vue warn]: Unknown custom element — that means Nova.booting never registered the component. The registration call in a 2018 bundle is the first thing to break across Nova majors.

The supply chain is the real cost. A compiled 2018 JS bundle of unknown provenance loading into an authenticated admin surface is unverifiable without source review and your own rebuild. The PHP side is harmless; the JS side is the review burden. If you can't justify that review, you can't justify the package.

Forking is trivially legal and usually the right move. MIT licence, ~100 lines of PHP plus one Vue component. Copy it into app/Nova/Fields/Tooltip.php, strip the stale Composer constraints, rebuild against a toolchain you control, and drop philperusse/nova-tooltip-field from composer.json. You keep the behaviour, lose the abandoned dependency, and gain something you can actually test and fix. Default to this over taking the vendor dependency.

Record the exception. If you do adopt it as published, put it in the dependency register with a named owner and a removal date tied to the next admin-panel upgrade. Unmaintained packages only become a problem when nobody remembers they're in the tree — the whole risk profile changes once the Nova upgrade ticket says "port or remove the tooltip field."

Debugging checklist when nothing renders: package installed (composer show | grep tooltip) → asset published/registered → component registered in Nova.booting (console) → field present in the Resource's fields() return → fillUsing no-op in place so the form isn't the thing that's broken. Work that order; it isolates vendor-side failures from your own wiring in about five minutes.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource