Copy Button
Accessible, unstyled clipboard copy button primitive.
| Package | @vizejs/ui/copy-button |
| Maturity | stable |
| Own the source | vize lib pull copy-button |
| Requires | — |
| Aliases | copy button, clipboard button, copy to clipboard, clipboard action |
| Covers | shadcn/ui Copy Button, React Aria Button, WAI-ARIA Button |
Usage
import { CopyButton } from "@vizejs/ui/copy-button";
Or copy the source into your project with vize lib pull copy-button (see Source Distribution).
API
CopyButton
Source: src/families/actions/copy-button/copy-button.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
as |
PrimitiveAs |
"button" |
Native element, custom element, or component to render. |
native |
boolean |
true when |
Whether the rendered target already implements native button semantics. |
type |
CopyButtonType |
"button" |
Native button submission behavior. |
value (required) |
string |
required |
Plain string copied to the system clipboard on activation. |
disabled |
boolean |
false |
Remove the control from activation and sequential keyboard focus. |
idleLabel |
string |
"Copy" |
Idle fallback text rendered when no default slot is supplied. |
copiedLabel |
string |
"Copied" |
Success fallback text rendered when no default slot is supplied. |
errorLabel |
string |
"Copy failed" |
Failure fallback text rendered when no default slot is supplied. |
ariaLabel |
string |
undefined |
Accessible name when no visible label or aria-labelledby supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the button. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe the button. |
writer |
CopyButtonWriter |
navigator.clipboard.writeText |
Test or platform hook for writing clipboard text. |
Events
| Event | Payload | Description |
|---|---|---|
copy |
[value: string, nativeEvent: MouseEvent] |
Fired after the configured writer accepts the value. |
error |
[error: unknown, value: string, nativeEvent: MouseEvent] |
Fired after the configured writer rejects the value. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
CopyButtonSlotState |
Renders button contents with the current copy state. |
Exposed
| Member | Type | Description |
|---|---|---|
value |
string |
Plain string that will be passed to the writer on activation. |
disabled |
boolean |
Whether the control suppresses user activation. |
writing |
boolean |
Whether an async write is already in flight. |
unavailable |
boolean |
Whether activation is currently unavailable. |
state |
CopyButtonState |
Stable copy result token for styling and tests. |
label |
string |
Resolved fallback text for the current state. |
element |
CopyButtonElement | null |
Rendered root element or component instance. |
focus |
(options?: FocusOptions) => void |
Move focus to the rendered control. |
Behavior
Normative state × input → outcome table for copy-button.vue.
| ID | Scenario | Behavior | Assertion |
|---|---|---|---|
| C1 | native render | renders a native button with type="button", part="root", label part, and idle state |
renders deterministic native button semantics and default label |
| C2 | default clipboard | activation writes the string through navigator.clipboard.writeText when available |
uses navigator.clipboard.writeText by default |
| C3 | successful write | accepts the configured writer, emits copy, and exposes data-state="copied" |
copies the configured value and exposes copied state |
| C4 | rejected write | catches writer failures, emits error, and exposes data-state="error" |
captures writer failures without throwing out of activation |
| C5 | disabled | native disabled removes activation; non-native disabled leaves tab order with ARIA state | disabled copy buttons suppress writes and keep platform semantics |
| C6 | labels and slots | label props and default slot receive the same strict idle | copied | error state |
supports custom labels and slot rendering |
| C7 | duplicate activation | a write in flight sets busy hooks and suppresses additional accidental writes | suppresses duplicate writes while a copy is in flight |
| C8 | non-native activation | non-native hosts expose button semantics and emulate native Enter/Space timing | non-native hosts preserve keyboard button activation |
| C9 | public instance | exposes live state, writing, unavailable, value, element, label, and focus() |
exposes live state and focus without broad clipboard abstractions |
| C10 | SSR and hydration | setup never touches browser globals; server markup is stable and hydrates without warnings | copy-button-ssr.test.ts and runtime conformance fixtures |
Contract
CopyButton is a headless action primitive for copying one plain string value.
It intentionally owns only a narrow clipboard write: the default writer calls
navigator.clipboard.writeText(value) at activation time, and tests or SSR
consumers may inject a writer prop. Component setup, SSR rendering, and
hydration do not access navigator, window, timers, or document globals.
The result state is closed to idle, copied, and error. Disabled and
in-flight writes are separate availability hooks through data-disabled,
data-writing, aria-disabled, aria-busy, slot state, and the public expose
contract. In-flight writes preserve focus rather than applying native disabled.
The rendered DOM exposes part="root" on the host and part="label" on the
fallback label span. Stable selectors are data-vize-ui="copy-button" and
data-vize-ui="copy-button-label". No CSS classes, runtime styles, CSS
custom properties, runtime CSS-in-JS, or copied value data attributes are
emitted; all visual styling remains consumer-owned.