COPY BUTTON: Clipboard-copy affordance with a success flash
VARIANTS: Reference number | URL share

.btn-copy composes .btn .btn-icon .btn-outline-secondary — it adds nothing but the success-state colour. data-controller="copy" writes the paired value to the clipboard, then flashes the button green with a check icon for two seconds and announces "Copied" to screen readers.

Reference Number

Reference number: Pairs with a read-only .form-control via data-copy-target="source" — the button reads the input's live value, not a static string, so the same markup works no matter what the reference number actually is.

Quote this reference when contacting admissions.

<div class="input-group" data-controller="copy">
  <input class="form-control" value="REF-2026-004821" readonly data-copy-target="source">
  <button class="btn btn-outline-secondary btn-icon btn-copy" aria-label="Copy reference number"
    data-copy-target="button" data-action="click->copy#copy">
    <i class="fa-regular fa-copy" aria-hidden="true" data-copy-target="icon"></i>
  </button>
  <span class="tw:sr-only" aria-live="polite" data-copy-target="status"></span>
</div>

URL Share

URL share: Same markup pattern for a shareable link. Try it — click the button to see the flash: .is-copied tints the button with the state-success trio and the icon swaps fa-regular fa-copyfa-solid fa-check for two seconds, then reverts.

Same data-controller="copy" contract — only the source input's value differs.

Quick Reference

Base: .btn-copy (composes .btn .btn-icon .btn-outline-secondary)
Success flash: .is-copied (state-success trio, applied by the controller for 2s)
Controller: data-controller="copy" | data-copy-target="source|button|icon|status" | click->copy#copy
Fallback: execCommand("copy") when the async Clipboard API is unavailable; a failed copy announces a manual-copy message via the status region instead of throwing