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

Copy Button Laravel Package

mrshanebarron/copy-button

mrshanebarron/copy-button is a Laravel Blade package for adding one-click copy-to-clipboard buttons to your views. Use it to let users copy text, links, or code snippets with minimal setup and adjustable styling, while avoiding custom JavaScript for common clipboard actions.

View on GitHub
Deep Wiki
Context7

Getting Started

The package ships a Blade component that renders a button wired to navigator.clipboard.writeText(). There is no runtime API to learn — the whole surface is "render the component, tell it what to copy."

Install:

composer require mrshanebarron/copy-button

Then check whether anything needs publishing (config, views, assets). Run php artisan vendor:publish with no arguments to see the available tags, or inspect the provider:

ls vendor/mrshanebarron/copy-button/src
cat vendor/mrshanebarron/copy-button/src/*ServiceProvider.php

If the button has styling or JS in a published asset, publish it and commit the result so the whole team shares one copy:

php artisan vendor:publish --tag=copy-button-assets   # confirm the real tag first
php artisan view:clear

First use case — a copyable install command on a docs/onboarding page:

<pre id="install-cmd">composer require mrshanebarron/copy-button</pre>

<x-copy-button target="#install-cmd" label="Copy command" />

or, when you already have the value in PHP and don't want a DOM lookup:

<x-copy-button :text="$project->api_key" label="Copy API key" />

Where to look first, in this order:

  1. src/View/Components/CopyButton.php — the constructor is the actual prop list (text vs target, label, maybe copiedLabel). Do not trust guessed prop names.
  2. The component's Blade view (resources/views/components/...) — tells you whether $attributes (and therefore class="...") is forwarded to the <button>.
  3. The JS — is it inline, a Vite entry, or a published file? This decides how you include it and whether a strict CSP will break it.
  4. Whether the provider registers the component or whether it lives in resources/views/components (anonymous). Anonymous components need nothing; class components need the provider auto-discovered.

Implementation Patterns

Two integration modes, chosen by data locality. Use text when the value comes from PHP (a token, a model field, a generated URL). Use target when the value already exists in the DOM (code samples, table cells) — the component reads it at click time, so it stays correct when Livewire/Alpine re-renders the source.

Copying real code blocks. Indentation inside a Blade template ends up inside the copied string. Keep snippets in a variable or partial and trim rather than inlining them in the markup:

@php
    $snippet = <<<'SH'
    php artisan migrate --seed
    SH;
@endphp

<pre id="cmd">{{ $snippet }}</pre>
<x-copy-button target="#cmd" label="Copy" />

Inside loops (order numbers, IDs). Unique targets only:

@foreach ($orders as $order)
    <span id="order-{{ $order->id }}">{{ $order->number }}</span>
    <x-copy-button target="#order-{{ $order->id }}" label="Copy" />
@endforeach

Wrap it once, use it everywhere. Given the package is a one-person, zero-star dependency, put it behind your own component so you can swap it later without touching 40 views:

{{-- resources/views/components/ui/copy.blade.php --}}
<x-copy-button
    :text="$text ?? null"
    :target="$target ?? null"
    label="{{ $label ?? 'Copy' }}"
    {{ $attributes->class(['btn btn-sm']) }}
/>

Passing structured/awkward values. Bind, don't interpolate, so quotes and & survive:

<x-copy-button :text="$payload" />                    {{-- fine --}}
<x-copy-button :text="json_encode($payload)" />       {{-- not {{ json_encode() }} --}}

Styling. If $attributes is merged onto the button, class="..." from the call site works. Otherwise publish the component view and edit it — never edit vendor/.

Testing. Feature tests can only assert markup; the copy itself is browser behaviour:

$this->get('/settings')
    ->assertSee('Copy API key')
    ->assertSee('data-target="#install-cmd"', false);   // or however the view emits it

For the real behaviour, use Dusk and stub the clipboard so you're not fighting permissions in CI:

$this->browse(fn ($browser) => $browser
    ->script('window.navigator.clipboard = { writeText: (t) => { window.__copied = t; } };')
    ->click('@copy-install')
    ->script('return window.__copied;'));

In Livewire / Turbo / Inertia pages. If the package binds handlers on DOMContentLoaded, they won't rebind after a soft navigation. Either re-init on the framework's event or, better, delegate the listener at document level in your own small script.

Gotchas and Tips

  • Secure context only. navigator.clipboard is undefined on plain http:// other than localhost. Testing on http://192.168.1.x on a phone will look like "the button does nothing." Serve over HTTPS or use a tunnel.
  • User gesture required. writeText() must run inside the click handler (transient activation). If you fetch the value first and copy in the .then(), Safari — and increasingly Chrome — rejects it. Copy synchronously from already-rendered text.
  • Hidden targets and fallbacks. If the package falls back to selection-based copying (document.execCommand), a display: none target copies an empty string. Use a visually-hidden technique instead of display:none if the element must be invisible.
  • v1.0.2 was a class-naming fix. Hyphenated component names now map to PascalCase PHP class files (copy-button → CopyButton.php). That matters on case-sensitive filesystems: if a stale differently-cased file is left behind after upgrading, <x-copy-button> can fail to resolve on Linux while working fine on macOS. Run your suite on a Linux runner and delete the old file; if you overrode the component, match the new casing.
  • Caches mask changes. After editing published views: php artisan view:clear. After config changes: php artisan config:clear. In production, php artisan optimize:clear — a cached compiled view is the usual reason "my edit did nothing."
  • Published assets go stale. If you published JS/CSS, a package update does not overwrite it. Decide deliberately: republish with --force after upgrades, or include the package asset from vendor/ directly.
  • Strict CSP. If the button is implemented via an inline onclick or an inline <script>, Content-Security-Policy without 'unsafe-inline' kills it silently in the console. Check the emitted markup; move the logic to a published file with a nonce if needed.
  • Accessibility is your job. The package gives a clickable button; it probably does not give you a live "Copied" announcement. Add aria-live="polite" feedback and keep a visible focus ring, or screen-reader users get no confirmation anything happened.
  • Duplicate ids from repeated components. Tooltips/labels keyed by id collide when you render many buttons; scope them or use $loop->index/$order->id.
  • Browser-only functionality has no backend test story. Don't try to prove the copy in a PHPUnit feature test. Assert the markup there, prove the behaviour in Dusk (or skip it and manually verify on release).
  • Vendor risk with a 0-star package. Pin the version ("mrshanebarron/copy-button": "^1.0"), keep the wrapper component so replacement is one file, and re-run a Dusk/manual check after any composer update. The extension points worth knowing: whether the component view is publishable, whether config controls the default label/CSS, and whether the JS is separable — if none are, your wrapper is the extension point.
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.
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen