earmsby's avatar

button/link to copy text to clipboard

I have a livewire component & blade which is used within a Filament 4.x application. The component retrieves some data about a Model called Publication and displays it to the user like this:

This information needs to be copied to a sheet outside the Filament app, so I'd love to have a button or link that when clicked would copy the six values (just the values separated by a comma) to the clipboard so they could more easily pasted in. This seems like it should be do-able but I'm not sure where to start on it. Any ideas?

0 likes
7 replies
LaryAI's avatar
Level 58

Certainly! You can achieve this easily by using a button with a small bit of Alpine.js (which comes with Filament out-of-the-box) and a hidden input or a computed string of the values you want to copy.

Here's a step-by-step solution:


1. Add an Alpine.js Data Block and Button

You'll construct the string from your variables and then use JavaScript to copy it to the clipboard.

Example Blade Snippet:

<div 
    x-data="{
        get values() {
            return [
                '{{ $fiveYearSales }}',
                '{{ $allTimeSales }}',
                '{{ $pageCount }}',
                '{{ $isDigitized }}',
                '{{ $lastPrintedBy }}',
                '{{ $monthSupply }}',
            ].join(',');
        },
        copy() {
            navigator.clipboard.writeText(this.values)
                .then(() => { $dispatch('notify', { type: 'success', message: 'Copied to clipboard!' }); })
                .catch(() => { $dispatch('notify', { type: 'danger', message: 'Copy failed!' }); });
        }
    }"
>
    <!-- ... your blade form ... -->

    <button 
        type="button"
        class="mt-4 px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
        x-on:click="copy"
    >
        Copy Info to Clipboard
    </button>
</div>

2. Explanation

  • The values getter concatenates your six variables, comma-separated.
  • The copy() function calls the Clipboard API to copy the string.
  • Optional: Use $dispatch('notify', ...) to let Filament's notification system alert the user.

3. Alternative Without Notifications

If you don't care about user feedback, simplify copy() to:

copy() { navigator.clipboard.writeText(this.values); }

4. No Alpine? Vanilla JS Fallback

Add a hidden input with the values, then attach a click handler to the button:

<input type="text" id="toCopy" value="{{ $fiveYearSales }},{{ $allTimeSales }},{{ $pageCount }},{{ $isDigitized }},{{ $lastPrintedBy }},{{ $monthSupply }}" style="position: absolute; left: -9999px;" readonly>
<button type="button" onclick="
    let copyText = document.getElementById('toCopy');
    copyText.select();
    document.execCommand('copy');
    alert('Copied!');
">Copy Info to Clipboard</button>

5. Final Notes

  • Recommended: Use the Alpine.js/Clipboard API approach for a modern, user-friendly experience in Filament.
  • Adapt the variable names as needed.
  • Works seamlessly inside your existing Blade template.

Let me know if you need a Livewire-based approach as well, but for user-triggered clipboard copying, Alpine/JS is ideal!

earmsby's avatar

I'd like to use the Alpine approach given, but when I implement it, I'm getting the error below in the JS console:

Alpine Expression Error: Cannot read properties of undefined (reading 'writeText')

Expression: "copy"

 <button type=​"button" class=​"mt-4 px-4 py-2 bg-blue-600 text-white rounded hover:​bg-blue-700" x-on:click=​"copy">​ Copy Info to Clipboard ​</button>​
normalErrorHandler @ livewire.js?id=0f6341c0:1133
handleError @ livewire.js?id=0f6341c0:1125
tryCatch @ livewire.js?id=0f6341c0:1121
(anonymous) @ livewire.js?id=0f6341c0:3933
handler4 @ livewire.js?id=0f6341c0:3235
(anonymous) @ livewire.js?id=0f6341c0:3299
(anonymous) @ livewire.js?id=0f6341c0:3237

I played around a little with logging a few values to the console in the copy() function like:

        console.log('Hello!');
        console.log({{ $fiveYearSales}});

The console showed Hello! but not the value of $fiveYearSales. I'm wondering if the values are not available because they are retrieved by livewire after a value is entered in the form?

earmsby's avatar
Level 6

I partially solved the problem. I didn't realize that the Alpine JS code navigator.clipboard.writeText(this.values) does not work on a local site running on Herd. When I deployed the code to the Forge server, I no longer got the error I described above. However, the text copied to the clipboard was simply ",,,,," - no values. So, I'm pretty sure that the values in

get values() {
            return [
                '{{ $fiveYearSales }}',
                '{{ $allTimeSales }}',
                '{{ $pageCount }}',
                '{{ $isDigitized }}',
                '{{ $lastPrintedBy }}',
                '{{ $monthSupply }}',
            ].join(',');
        },

are calculated when the component first loads and don't update when they are calculated by livewire (whenever $sku or $current_qty is updated on the form.

I'm going to try a hybrid approach and set the value of a hidden input with the comma-delimited string and use that to copy to the clipboard instead of the get values() method in Larry AI's example. We'll see if that works.

aleahy's avatar

The most likely reason you can't get it to work on it locally is that the navigator.clipboard requires https to work.

Get herd to issue a local ssl cert by running herd secure from the cli.

Then you should be able to debug locally in peace.

1 like
Glukinho's avatar

This is wrong, localhost pages are considered secure along with https ones, for dev purposes. Clipboard should work locally.

earmsby's avatar

Thanks, I didn't know you could do that with Herd.

earmsby's avatar

I ended up adding a new livewire attribute $clipboardText. Then I was able to calculate that along with the other values. In the blade I used:

This works fine except that

                .then(() => { $dispatch('notify', { type: 'success', message: 'Copied to clipboard!' }); })
                .catch(() => { $dispatch('notify', { type: 'danger', message: 'Copy failed!' }); });

Didn't give me any notifications so I just added the clunky alert('copied!'); instead. Not elegant but gets done what I needed.

Please or to participate in this conversation.