Skip to content

v-copy ​

Click an element to copy it. With no value it copies the element's own text; with one it copies that instead.

Open in demo

Registration ​

Registered globally in a project built from the template, so there is nothing to import:

ts
app.directive('copy', vCopy)

To use it in one component instead, import it and Vue picks up the v prefix automatically:

ts
import { vCopy } from '@shared/directives/vCopy'

Usage ​

vue
<template>
  <code v-copy>npm create smart-admin@latest</code>

  <button type="button" v-copy="order.reference">
    Copy reference
  </button>
</template>
FormWhat it copies
v-copyThe element's textContent.
v-copy="value"The bound string.

Example ​

vue
<script setup lang="ts">
import { ref } from 'vue'

const apiKey = ref('pk_demo_1a2b3c4d5e6f7g8h9i0j')
</script>

<template>
  <div class="flex items-center gap-3">
    <code v-copy class="rounded border px-2 py-1">{{ apiKey }}</code>

    <button type="button" v-copy="apiKey">
      Copy key
    </button>
  </div>
</template>

Notes ​

  • The bound value is read at click time, not at bind time, so a :value that changes is always copied as it is now. That is why there is no updated hook.
  • It sets cursor: pointer on the element, so a <code> block looks clickable without you styling it.
  • A success toast says "Copied"; a failure toast says the copy failed. Both are translation keys, so they follow the language switcher.
  • Clipboard writes can be refused. navigator.clipboard.writeText needs a secure context and, in some browsers, a permission. The rejection is caught and toasted rather than thrown.
  • The click handler is stashed on the element so unmounted can remove it. Without that, every mount would leak a listener.
  • v-permission — the other shipped directive.
  • Toasts — what the confirmation is drawn with.