inspheric/nova-url-field
A URL field for Laravel Nova that displays URLs as clickable, copyable links in index, detail, and form views. Customize link text, target, and styling while storing values as plain strings, keeping long URLs readable and letting users open or copy them with one click.
composer require inspheric/nova-url-field — then pin explicitly: ^3.0 on Nova 5, ^2.0.2 on Nova 4. The package major is the Nova major. Do not float ("inspheric/nova-url-field": "*") and do not assume v3.0 is a drop-in upgrade from v2.x; the release notes only say Nova 5 support was added and say nothing about what was dropped or whether the PHP floor moved. Diff the composer.json between the two tags before committing.config/ publish, no migrations, no compiled assets, no nova:publish step. The whole package is a field class plus its Vue component. "Installed" means the composer require succeeded.fields() method. That is the entire integration surface. Import Inspheric\NovaUrlField\Url and swap whatever Text::make('Website') you already have.composer.json's http-basic/nova config or composer install dies before a single test runs.website / homepage / docs_url column on a resource admins actually browse. You get a plain text input on create/edit, and a clickable anchor on index and detail, for free.use Inspheric\NovaUrlField\Url;
public function fields(NovaRequest $request)
{
return [
Url::make('Website')
->rules('url', 'max:255')
->nullable(),
];
}
First milestone: open the index, click the link, open the detail view, click the link, then edit the record, blank the field, save, and reload. That last step is the one that regresses across majors — verify it explicitly on your Nova version before converting a second resource.
Text::make('Website')->displayUsing(fn ($v) => "<a href=\"{$v}\">…</a>") (or worse, ->asHtml()), this package is the clean swap. Same database column, same stored value, zero migration. Rollback is a one-line revert per field, which is what makes opportunism safe here.url rule rejects example.com (no scheme). Rather than teaching admins to type https://, add a small mutator or Attribute cast that prepends https:// when no scheme is present. Then ->rules('url') passes, the anchor href is valid, and sorting is at least consistent.protected function website(): Attribute
{
return Attribute::make(
set: fn (?string $value) => $value && ! str_contains($value, '://')
? 'https://'.$value
: $value,
);
}
->rules('url', 'max:255'), ->nullable(), and a starts_with:http,https if the column accepts untrusted input. Avoid active_url — it does a DNS lookup on every save.->nullable() on the field and a nullable column. Without it, an empty submit stores '', and an <a href=""> renders as a link back to the current admin page. This is the single most common "the field is broken" report.->onlyOnDetail() for long URLs with query strings that wreck the index table, ->hideFromIndex() for callback/webhook endpoints nobody needs to click from a list, ->sortable() only when the ordering is actually meaningful (see Gotchas).->canSee(), not conditional markup. Published-only links, admin-only vendor portals, per-tenant links — resolve them in the resource or in canSee(). Don't try to build markup inside the field.->copyable() is genuinely useful on endpoint/webhook URL columns. ->help() for format hints. ->textAlign('left') so the index column doesn't inherit Nova's default alignment and look misaligned next to text fields.canSee behavior. Then generalize.assertSee, Nova::assertFields) rather than HTTP-level DOM scraping. If you write a feature test that hits the detail screen, assert on the href attribute, not on "the page contains the URL" — the raw string appears in the form field too.composer update simply won't take v3.0 — and forcing it breaks the field. Annotate your internal dependency allowlist with "Nova 5+ only." Read the composer.json diff between v2.0.2 and v3.0 to find the real dropped-version and PHP constraints; the release notes are an information gap, not a specification.javascript: and data: payloads can survive any rule that only checks URL shape. Add starts_with:http,https or an explicit allowlist, and confirm target="_blank" anchors carry rel="noopener noreferrer". The v3.0 notes make no claim either way — assume nothing and check the rendered markup yourself.VARCHAR(255) is the usual culprit when long query-string URLs truncate silently (or throw in strict SQL mode). It looks like a rendering bug and isn't.'' vs null — again, because it's the #1 false alarm. Empty string → anchor to the current page → "your package is broken."https://a.com and www.a.com sort miles apart and domains are ignored entirely. Don't expose ->sortable() on a link column if admins expect domain grouping — or normalize schemes first, which at least removes the worst of it.->displayUsing() on top of it. The field's whole value is the anchor it renders. If you replace the display, you're back to hand-rolled markup and you've lost the reason you added the dependency.dd() / tinker the raw database value — is it null, '', or a schemeless string? (2) check the field isn't hidden by canSee or an onlyOn* method; (3) view-source the rendered anchor in the browser to see what href actually got emitted; (4) confirm the installed major matches your Nova major via composer show inspheric/nova-url-field. Nova caches nothing exotic here, so a stale-component problem is rare — the stored value and the visibility rules are almost always it.rel enforcement baked in, subclass Inspheric\NovaUrlField\Url and override resolve/meta. Document that path in your team wiki: it turns an upstream stall or a future Nova-major break into a two-hour task instead of a rewrite.Text field or a fifty-line custom field. That cheap exit is the main reason this dependency is safe to adopt.How can I help you explore Laravel packages today?