Clipboard
The clipboard machine allows users to quickly copy content to clipboard.
Installation
To use the clipboard machine in your project, run the following command in your command line:
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
To set up the clipboard correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM`.
Usage
First, import the clipboard package into your project
import * as clipboard from "@zag-js/clipboard"
The clipboard package exports two key functions:
machine— The state machine logic for the clipboard widget.connect— The function that translates the machine's state to JSX attributes and event handlers.
You'll also need to provide a unique
idto theuseMachinehook. This is used to ensure that every part has a unique identifier.
Next, import the required hooks and functions for your framework and use the clipboard machine in your project 🔥
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 { useMachine, normalizeProps } 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/react" import { ClipboardCheck, ClipboardCopyIcon } from "lucide-svelte" import { useId } from "react" 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()}> {api.copied ? <ClipboardCheck /> : <ClipboardCopyIcon />} </button> </div> </div>
Setting the clipboard value
You can set the value to copy by passing a value prop to the machine
context.
const service = useMachine(clipboard.machine, { value: "Hello, world!", })
Listening to copy events
When the value is copied to the clipboard, the onStatusChange event is fired.
You can listen to this event and perform any action you want.
const service = useMachine(clipboard.machine, { onStatusChange: (details) => { console.log("Copy status changed to", details.copied) }, })
Checking if the value is copied
Use the api.copied property to check if the value is copied to the clipboard.
const api = clipboard.connect(service) if (api.copied) { console.log("Value is copied to the clipboard") }
Changing the timeout
By default, the clipboard machine will automatically reset the state to idle
after 3000ms. You can change this timeout by passing a timeout option to the
machine context.
const service = useMachine(clipboard.machine, { timeout: 5000, })
Styling guide
Earlier, we mentioned that each clipboard part has a data-part attribute added
to them to select and style them in the DOM.
[data-scope="clipboard"][data-part="root"] { /* styles for the root part */ }
Methods and Properties
Machine Context
The clipboard machine exposes the following context properties:
idsPartial<{ root: string; input: string; label: string; }>The ids of the elements in the clipboard. Useful for composition.valuestringThe controlled value of the clipboarddefaultValuestringThe 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) => voidThe function to be called when the value changesonStatusChange(details: CopyStatusDetails) => voidThe function to be called when the value is copied to the clipboardtimeoutnumberThe timeout for the copy operationidstringThe unique identifier of the machine.getRootNode() => ShadowRoot | Node | DocumentA 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
Data Attributes
Edit this page on GitHub