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 Text Copy Field Laravel Package

sixlive/nova-text-copy-field

A Laravel Nova field that displays text with a one-click copy-to-clipboard button, making it easy for users to grab URLs, IDs, tokens, and other values from the admin panel without manual selection. Simple to install and customize.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and confirm you're on a supported Nova major — in that order.

composer require sixlive/nova-text-copy-field

There is nothing else to wire up: no service provider, no config file to publish, no migration, no artisan command. The package ships a PHP field class plus a pre-compiled Vue bundle under dist/ that Nova picks up through its standard custom-field asset mechanism. If the copy button doesn't render after composer require, the fix is a Nova asset refresh (php artisan nova:publish, clear compiled views, hard refresh), not a registration step.

Where to look first, in this order:

  1. vendor/sixlive/nova-text-copy-field/composer.json — check the declared php, laravel/framework, and nova constraints. The last release is 2019-03-03, which is pre-Nova-4 and pre-Vue-3. This is your go/no-go gate. Prove it renders on your Nova major in a dev environment before writing it into any resource.
  2. vendor/sixlive/nova-text-copy-field/src/ — the field class is a short Laravel\Nova\Fields\Text subclass. Read it end-to-end. Confirm the namespace and FQCN with a quick grep -r "class TextCopy" vendor/sixlive/nova-text-copy-field/src rather than trusting the README or a blog post, and note exactly which withMeta() props it forwards to the Vue component and which fluent setters it exposes.
  3. vendor/sixlive/nova-text-copy-field/resources/js/components/ — which Nova field contexts does the component implement (IndexField, DetailField, FormField)? How is the clipboard call made (navigator.clipboard vs. an execCommand fallback)? Is there an aria-label, a success state, an error state?
  4. dist/js/field.js — this is what Nova actually loads. If resources/js and dist/ have drifted (common in single-maintainer packages), dist/ is the truth.

First use case: one field, one resource, detail view only.

Pick a single read-only value your team genuinely transcribes by hand — an external account ID, a public invite URL, a slug. Swap the field and change nothing else:

use Sixlive\TextCopy\TextCopy;   // verify FQCN against src/ first
// was: use Laravel\Nova\Fields\Text;

public function fields(Request $request)
{
    return [
        ID::make()->sortable(),

        TextCopy::make('External Account ID', 'external_account_id')
            ->onlyOnDetail()
            ->readonly(),

        // ... everything else unchanged
    ];
}

Smoke-test that one field on the detail view before you touch a second resource. Adoption is reversible one line at a time; keep it that way so you always have a clean rollback.

Implementation Patterns

Scope the field per context, not per resource. The copy affordance in v1.5.0 reaches create/edit forms too, but you rarely want the same treatment everywhere. Use Nova's standard visibility modifiers instead of building conditionals into the field:

TextCopy::make('Webhook Secret', 'webhook_secret')
    ->onlyOnDetail()
    ->canSee(fn (Request $request) => $request->user()->can('viewSecrets', $this->resource)),

TextCopy::make('Slug', 'slug')
    ->exceptOnForms()
    ->sortable(),                    // still a Text subclass; index sorting works

TextCopy::make('Public Invite URL')
    ->onlyOnForms()
    ->readonly()
    ->help('Click the copy icon to grab the link.'),

->help() earns its keep here — an icon-only copy button with no label is ambiguous to anyone who didn't build it.

Use resolveUsing for the value an operator actually wants on the clipboard. The most common real need isn't the raw column; it's the fully-formed string:

TextCopy::make('Invite Link')
    ->resolveUsing(fn () => route('invites.accept', $this->resource->invite_token))
    ->onlyOnDetail()
    ->readonly(),

Because this is display-only, resolveUsing is safe — no write-back concern. If you need a writable copyable field, keep the underlying column as the source of truth and let the field write normally.

"Generate, then copy" flow. On a create form the field renders an input whose value is whatever form state holds at that moment — an empty token column is an empty copyable value. The pattern that works is to generate in the model and send the operator to the detail view:

// app/Models/ApiKey.php
protected static function booted()
{
    static::creating(function ($key) {
        $key->token = $key->token ?: Str::random(48);
    });
}
// Nova resource
TextCopy::make('Token')
    ->onlyOnDetail()          // populated post-save, copied immediately
    ->readonly()
    ->help('Shown for convenience — not masked.'),

Standardize the convention via an internal field, not by hand-rolling config. If copyable values appear on more than two or three resources, wrap it once so a later change (label, help text, aria copy, swapping the package out entirely) is a single-file edit:

namespace App\Nova\Fields;

use Sixlive\TextCopy\TextCopy;

class CopyableValue extends TextCopy
{
    public function __construct($name, $attribute = null, $resolveCallback = null)
    {
        parent::__construct($name, $attribute, $resolveCallback);

        $this->onlyOnDetail()->readonly();

        // Verify the setter name against src/ before relying on it.
        if (method_exists($this, 'copyButtonLabel')) {
            $this->copyButtonLabel('Copy');
        }
    }
}

This wrapper is also your exit ramp: if the field breaks on a Nova upgrade, you reimplement CopyableValue once as a native Text with your own Vue component and every resource keeps working.

Index-console placement is the highest-value use, when it works. For support/ops tables, an operator reading a ticket can copy an account ID straight from the row without opening the record. That only works if the component implements IndexField — confirm it before promising it. If it doesn't, use ->onlyOnDetail() and put a link to the record in the index.

Smoke matrix before rollout. Per resource, per context — index, detail, create, edit — over HTTPS, and over plain HTTP in any environment where that applies, so you learn what "silently does nothing" looks like. Run it once with the browser console open; a 404 on the field bundle is a two-second diagnosis that otherwise reads as "the copy button is broken."

Gotchas and Tips

Nova-major compatibility is the real risk, not the code quality. A 2019 field bundle predates Nova 4's Vue 3 migration. Symptoms range from "field renders as plain text with no button" to a Nova asset build that fails outright. Test on your exact Nova major in dev first; if it breaks, decide immediately between (a) patching the component to your Vue version, or (b) generating a native field with php artisan nova:field acme/copyable-text and porting ~100 lines. Both are hours, not days — you just don't want to find out mid-rollout.

navigator.clipboard requires a secure context. Over plain HTTP — or any non-localhost, non-HTTPS origin — the modern Clipboard API is unavailable. If the component has no execCommand fallback, the button fails silently. Confirm the admin panel is HTTPS in every environment where copying matters, including internal/staging boxes reached by bare IP. Silent failure produces support tickets that look like a code bug and aren't.

Empty values on create forms are the second-most-common surprise. The button copies the input's current content. On a create form for a value that doesn't exist until save, the operator copies "" and walks away thinking it worked. Either generate the value pre-render (observer pattern above) or scope the field to detail views.

readonly() changes the rendered markup. Nova renders readonly fields differently in form contexts. Verify the copy button still appears and is still clickable in that combination — it's exactly what you'll reach for on forms, and exactly what the original author is least likely to have tested.

Don't assume Text behaviors carry over. This is a subclass with its own Vue component, and the component author's props — not Nova's — decide what works. ->displayUsing(), ->asHtml(), custom ->withMeta() props, index truncation, any copyable/toggle modifiers: all may simply be unimplemented. Read resources/js/components/ and only use what is actually forwarded. When you need something the component doesn't support, use plain Text and accept the missing button rather than hacking around it in the resource.

Asset caching will make you think your change didn't apply. After composer update or any edit, run php artisan nova:publish, clear compiled views, and hard-refresh. Nova caches to public/vendor/ and browsers cache the field bundle aggressively.

Pin the exact version and name an owner. "sixlive/nova-text-copy-field": "1.5.0" — not ^1.5, not *. Single maintainer, zero dependents, no release since March 2019. The honest classification in your dependency register is "disposable": review on every Nova major upgrade, not on a calendar. That trigger is the entire maintenance story.

Treat it as a convenience, not a control. No masking, no reveal-on-demand, no audit trail, no rotation. If the value is genuinely sensitive, a copy button is the wrong affordance and will lull reviewers into thinking it's handled. Show a masked/truncated value with an explicit reveal action, and keep real secrets out of Nova fields where you can.

Check the accessibility basics by hand, once. Tab to the button — is it focusable? Read it with a screen reader — does it announce "copy" rather than nothing? After clicking, is there a visible (not color-only) success state? Icon-only copy buttons from that era routinely fail all three.

Debugging checklist when the button doesn't appear, in order:

  1. Browser console — 404 on the field's JS?
  2. php artisan nova:publish + hard refresh.
  3. Inspect the DOM — is the custom component rendering, or has it degraded to a plain text input?
  4. Does your Nova version's field-component contract match what the package implements?
  5. Swap back to Text::make() to confirm the rest of the resource is fine, isolating the failure to this one field.
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