v-copy
Click an element to copy it. With no value it copies the element's own text; with one it copies that instead.
vue
<script setup lang="ts">
import { vCopy } from '@shared/directives/vCopy'
import { Button } from '@shared/components/ui/button'
import { ref } from 'vue'
const reference = ref('INV-2026-0418')
</script>
<template>
<div class="flex flex-wrap items-center gap-3">
<code v-copy class="rounded-md border border-border px-2 py-1 sa-text-sm">
npm run smart-admin -- analyze
</code>
<Button v-copy="reference" size="sm" variant="outline">
Copy {{ reference }}
</Button>
</div>
</template>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>| Form | What it copies |
|---|---|
v-copy | The 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
:valuethat changes is always copied as it is now. That is why there is noupdatedhook. - It sets
cursor: pointeron 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.writeTextneeds 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
unmountedcan remove it. Without that, every mount would leak a listener.
Related
v-permission— the other shipped directive.- Toasts — what the confirmation is drawn with.