Clipboard
The clipboard machine lets users quickly copy content to the clipboard.
Installation
Install the clipboard package:
npm install @zag-js/clipboard @zag-js/react # or yarn add @zag-js/clipboard @zag-js/react
npm install @zag-js/clipboard @zag-js/solid # or yarn add @zag-js/clipboard @zag-js/solid
npm install @zag-js/clipboard @zag-js/vue # or yarn add @zag-js/clipboard @zag-js/vue
npm install @zag-js/clipboard @zag-js/svelte # or yarn add @zag-js/clipboard @zag-js/svelte
Anatomy
Check the clipboard anatomy and part names.
Each part includes a
data-partattribute to help identify them in the DOM.
Usage
Import the clipboard package:
import * as clipboard from "@zag-js/clipboard"
The clipboard package exports two key functions:
machine- State machine logic.connect- Maps machine state to JSX props and event handlers.
Pass a unique
idtouseMachineso generated element ids stay predictable.
Then use the framework integration helpers:
import * as clipboard from "@zag-js/clipboard" import { useMachine, normalizeProps } from "@zag-js/react" import { ClipboardCheck, ClipboardCopyIcon } from "lucide-react" import { useId } from "react" function Clipboard() { const service = useMachine(clipboard.machine, { id: useId(), value: "https://github.com/chakra-ui/zag", }) const api = clipboard.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Copy this link</label> <div {...api.getControlProps()}> <input {...api.getInputProps()} /> <button {...api.getTriggerProps()}> {api.copied ? <ClipboardCheck /> : <ClipboardCopyIcon />} </button> </div> </div> ) }
import * as clipboard from "@zag-js/clipboard" import { useMachine, normalizeProps } from "@zag-js/solid" import { ClipboardCheck, ClipboardCopyIcon } from "lucide-solid" import { createMemo, createUniqueId } from "solid-js" function Clipboard() { const service = useMachine(clipboard.machine, { id: createUniqueId(), value: "https://github.com/chakra-ui/zag", }) const api = createMemo(() => clipboard.connect(service, normalizeProps)) return ( <div {...api().getRootProps()}> <label {...api().getLabelProps()}>Copy this link</label> <div {...api().getControlProps()}> <input {...api().getInputProps()} /> <button {...api().getTriggerProps()}> <Show when={api().copied} fallback={<ClipboardCopyIcon />}> <ClipboardCheck /> </Show> </button> </div> </div> ) }
<script setup> import * as clipboard from "@zag-js/clipboard" import { normalizeProps, useMachine } from "@zag-js/vue" import { ClipboardCheck, ClipboardCopyIcon } from "lucide-vue-next" import { computed } from "vue" const service = useMachine(clipboard.machine, { id: "1", value: "https://github.com/chakra-ui/zag", }) const api = computed(() => clipboard.connect(service, normalizeProps)) </script> <template> <div v-bind="api.getRootProps()"> <label v-bind="api.getLabelProps()">Copy this link</label> <div v-bind="api.getControlProps()"> <input v-bind="api.getInputProps()" style="width: 100%" /> <button v-bind="api.getTriggerProps()"> <ClipboardCheck v-if="api.copied" /> <ClipboardCopyIcon v-else /> </button> </div> </div> </template>
<script lang="ts"> import * as clipboard from "@zag-js/clipboard" import { useMachine, normalizeProps } from "@zag-js/svelte" import { ClipboardCheck, ClipboardCopyIcon } from "lucide-svelte" const id = $props.id() const service = useMachine( clipboard.machine, ({ id: id, value: "https://github/com/chakra-ui/zag", }), ) const api = $derived(clipboard.connect(service, normalizeProps)) </script> <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Copy this link</label> <div {...api.getControlProps()}> <input {...api.getInputProps()} /> <button {...api.getTriggerProps()}> {#if api.copied} <ClipboardCheck /> {:else} <ClipboardCopyIcon /> {/if} </button> </div> </div>
Setting the clipboard value
Set value to control what gets copied.
const service = useMachine(clipboard.machine, { value: "Hello, world!", })
Setting an initial value
Use defaultValue for uncontrolled initial value.
const service = useMachine(clipboard.machine, { defaultValue: "Hello, world!", })
Listening for value changes
Use onValueChange to react when the clipboard value changes.
const service = useMachine(clipboard.machine, { onValueChange(details) { console.log("Value changed to", details.value) }, })
Listening to copy events
When the value is copied, onStatusChange is fired.
const service = useMachine(clipboard.machine, { onStatusChange: (details) => { console.log("Copy status changed to", details.copied) }, })
Checking if the value is copied
Use api.copied to check if the value was copied.
const api = clipboard.connect(service) if (api.copied) { console.log("Value is copied to the clipboard") }
Changing the timeout
By default, the copied feedback resets after 3000ms. Set timeout to change
this delay.
const service = useMachine(clipboard.machine, { timeout: 5000, })
Styling guide
Each part includes a data-part attribute you can target in CSS.
[data-scope="clipboard"][data-part="root"] { /* styles for the root part */ }
Methods and Properties
Machine Context
The clipboard machine exposes the following context properties:
translationsIntlTranslations | undefinedSpecifies the localized strings that identifies the accessibility elements and their statesidsPartial<{ root: string; input: string; label: string; }> | undefinedThe ids of the elements in the clipboard. Useful for composition.valuestring | undefinedThe controlled value of the clipboarddefaultValuestring | undefinedThe initial value to be copied to the clipboard when rendered. Use when you don't need to control the value of the clipboard.onValueChange((details: ValueChangeDetails) => void) | undefinedThe function to be called when the value changesonStatusChange((details: CopyStatusDetails) => void) | undefinedThe function to be called when the value is copied to the clipboardtimeoutnumber | undefinedThe timeout for the copy operationidstringThe unique identifier of the machine.getRootNode(() => ShadowRoot | Node | Document) | undefinedA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.
Machine API
The clipboard api exposes the following methods:
copiedbooleanWhether the value has been copied to the clipboardvaluestringThe value to be copied to the clipboardsetValue(value: string) => voidSet the value to be copied to the clipboardcopyVoidFunctionCopy the value to the clipboard