use-clipboard
Permission-aware clipboard access with a legacy copy fallback.
| Package | @vizejs/composable/use-clipboard |
| Own the source | vize lib pull composable:use-clipboard |
| Runtime exports | useClipboard |
| Gzip budget | 4096 B |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/composable
Import the entry directly. Call lifecycle-bound utilities inside <script setup> so cleanup follows the component scope; consult the runtime contract for this entry's SSR and hydration behavior.
import { useClipboard } from "@vizejs/composable/use-clipboard";
Try it
Copy and read an editable install command
Report the outcome of an explicit clipboard operation while keeping the last successful text and time-limited copy feedback separate.
What to observe: Edit Install command, then activate Copy install command. The readout reports the actual mechanism and recent-copy feedback expires after 1.5 seconds. Read clipboard text requests a read only when activated. If your browser refuses permission, the failure is displayed while the last successful text remains.
This example uses the real default browser host; it never supplies a fake clipboard. Copy writes to your clipboard. The async Clipboard API normally requires a secure context and browser permission; legacy copying may still be available where reading is not. supported means at least one copying mechanism exists, not that reading is permitted. Every action resolves to a discriminated result instead of rejecting. A later success clears the last error; reading does not restart the copied timer. During SSR no clipboard or permission is read, text is empty, and support is false. The mounted host resolves after the initial hydration render. Scope disposal owns the copied reset timer.
Compare the initial and interacted states


Copy the example
Save this complete SFC in your Vue project. Its public imports and source are the same ones executed in the preview.
<script setup lang="ts">
import { ref, useId } from "vue";
import { useClipboard } from "@vizejs/composable/use-clipboard";
const commandId = useId();
const command = ref("vp add @vizejs/composable vue");
const outcome = ref("No clipboard operation yet.");
const { supported, text, copied, error, readPermission, copy, readText } = useClipboard();
async function copyCommand(): Promise<void> {
const result = await copy(command.value);
outcome.value =
result.status === "success"
? `Copied using ${result.method}.`
: `Copy did not complete: ${result.status}.`;
}
async function readClipboard(): Promise<void> {
const result = await readText();
outcome.value =
result.status === "success"
? "Read the clipboard text."
: `Read did not complete: ${result.status}.`;
}
</script>
<template>
<div class="composable-example">
<label :for="commandId">Install command</label>
<input :id="commandId" v-model="command" />
<div class="example-actions">
<button type="button" :disabled="!supported" @click="copyCommand">
Copy install command
</button>
<button type="button" :disabled="!supported" @click="readClipboard">
Read clipboard text
</button>
</div>
<output aria-live="polite">{{ outcome }} Recently copied: {{ copied ? "yes" : "no" }}.</output>
<p class="clipboard-result">
Last successful text: <code>{{ text || "None yet." }}</code>
</p>
<p>
Clipboard read permission: {{ readPermission }} · Last failure: {{ error?.status || "none" }}
</p>
<p>
Copy writes the editable command to your clipboard. Read requests your clipboard text only
when you activate its button. Permission failures keep the previous successful text.
Recent-copy feedback expires after 1.5 seconds; reading does not restart it.
</p>
<p v-if="!supported">Clipboard support is not available in this context.</p>
</div>
</template>
<style scoped>
.clipboard-result {
overflow-wrap: anywhere;
}
</style>
Runtime contract
| Utility | Category | Stability | SSR | Hydration | Cleanup | Targets | Host globals | Uses |
|---|---|---|---|---|---|---|---|---|
useClipboard |
system | experimental | deterministic-fallback | stable | reactive-scope | web, desktop | globalThis, window |
tryOnScopeDispose, usePermission |
API
useClipboard
Permission-aware clipboard access with a legacy copy fallback. Text and rich items go through the async Clipboard API. When it is missing (insecure contexts, older engines) or refuses a write, copy falls back to document.execCommand("copy") unless legacy is false. Every action resolves to a discriminated ClipboardResult ("success", "permission-denied", "unsupported", "failed") instead of rejecting, and the read/write permission states are exposed reactively. Server rendering: nothing is read and no permission is queried; text is empty and supported is false. The copied reset timer and the optional copy/cut listeners are released when the owning scope stops. Inside a component the host is read after mounting, so hydration renders the server fallback first and never mismatches.
function useClipboard(options: UseClipboardOptions = {}): ClipboardControls
const { copy, copied } = useClipboard();
await copy("npm i
## Types
### `ClipboardItemLike`
One clipboard entry, compatible with the DOM `ClipboardItem`.
| Member | Type | Description |
| --- | --- | --- |
| `types` | `readonly string[]` | MIME types available in this item. |
| `getType` | `(type: string) => Promise<Blob>` | Read the item's data for one of its `types`. |
### `ClipboardLike`
Minimal async Clipboard API consumed by `useClipboard`.
| Member | Type | Description |
| --- | --- | --- |
| `readText` | `() => Promise<string>` | Read plain text. |
| `writeText` | `(text: string) => Promise<void>` | Write plain text. |
| `read`? | `() => Promise<readonly ClipboardItemLike[]>` | Read rich items. Absent in older browsers. |
| `write`? | `(items: readonly ClipboardItemLike[]) => Promise<void>` | Write rich items. Absent in older browsers. |
### `ClipboardHost`
Capabilities used by `useClipboard`; every member is optional.
| Member | Type | Description |
| --- | --- | --- |
| `clipboard`? | `ClipboardLike \| null` | Async Clipboard API (`navigator.clipboard`). |
| `permissions`? | `PermissionsHost \| null` | Permissions API used to report read/write permission state. |
| `legacyCopy`? | `((text: string) => boolean) \| null` | Synchronous legacy copy used when the async API is missing or refuses. Returns whether the copy succeeded. |
| `events`? | `EventTarget \| null` | Target of `copy`/`cut` events observed when `listen` is enabled. |
### `ClipboardSuccess`
Successful clipboard operation.
| Member | Type | Description |
| --- | --- | --- |
| `status` | `"success"` | The operation succeeded. |
| `value` | `Value` | Value that was read or written. |
| `method` | `"clipboard" \| "legacy"` | Mechanism that performed the operation. |
### `ClipboardFailure`
Failed clipboard operation.
| Member | Type | Description |
| --- | --- | --- |
| `status` | `ClipboardFailureReason` | Why the operation failed. |
| `error` | `unknown` | Exact error thrown by the host, when one was thrown. |
### `UseClipboardOptions`
Options for `useClipboard`.
| Member | Type | Description |
| --- | --- | --- |
| `host`? | `MaybeRefOrGetter<ClipboardHost \| null \| undefined>` | Clipboard capabilities for alternate runtimes and tests. |
| `legacy`? | `boolean` | Fall back to `document.execCommand("copy")` when the async API is unavailable or rejects a write. |
| `copiedDuringMs`? | `number` | Milliseconds for which `copied` stays `true` after a successful write. |
| `scheduler`? | `TimeoutScheduler` | Timer host used to reset `copied`. |
| `listen`? | `boolean` | Update `text` by reading the clipboard after every `copy`/`cut` event. |
| `queryPermissions`? | `boolean` | Query the `clipboard-read` / `clipboard-write` permissions. |
### `ClipboardControls`
Reactive state and actions returned by `useClipboard`.
| Member | Type | Description |
| --- | --- | --- |
| `supported` | `ComputedRef<boolean>` | Whether the async Clipboard API or the legacy fallback is available. |
| `text` | `Readonly<Ref<string>>` | Text most recently copied or read. |
| `copied` | `Readonly<Ref<boolean>>` | `true` for `copiedDuringMs` after a successful copy. |
| `error` | `Readonly<ShallowRef<ClipboardFailure \| undefined>>` | Most recent failure, cleared by the next success. |
| `readPermission` | `Readonly<Ref<PermissionQueryState>>` | State of the `clipboard-read` permission. |
| `writePermission` | `Readonly<Ref<PermissionQueryState>>` | State of the `clipboard-write` permission. |
| `copy` | `(text: string) => Promise<ClipboardResult<string>>` | Copy text, falling back to the legacy mechanism when allowed. |
| `readText` | `() => Promise<ClipboardResult<string>>` | Read plain text. |
| `writeItems` | `( items: readonly ClipboardItemLike[], ) => Promise<ClipboardResult<readonly ClipboardItemLike[]>>` | Write rich clipboard items. |
| `readItems` | `() => Promise<ClipboardResult<readonly ClipboardItemLike[]>>` | Read rich clipboard items. |