Dots

Copy Field

A label, a value and a copy button for account numbers, card details, references and addresses.

Account holderAlex Morgan
Account number0001 2345 6789
Routing number021000021
ReferenceInvoice 2041
import { CopyField } from "@/components/ui/copy-field"

export function CopyFieldDemo() {

The CopyField component shows one value with its label and a button that copies it. Use it for bank details, card numbers, wallet addresses and payment references that people paste into another app. Stack several in a card or sheet; the field has no background of its own. Pick it over a read-only Input when the value is only there to be copied, and over a KeyValue row when copying is the main action.

Installation

pnpm dlx shadcn@latest add @dots/copy-field

Usage

import { CopyField } from "@/components/ui/copy-field"
<CopyField label="Routing number" value="021000021" mono />

Features

  • Copies the exact value while showing a friendlier displayValue
  • Monospace, tabular digits for numbers and codes that wrap at any character
  • Masking that hides all but the last characters and still copies the real value
  • A large size for one-time and pairing codes
  • The button icon turns to a check on success and an alert on failure, then resets after 2 seconds
  • Copy results are announced through a polite live region
  • A disabled state that keeps the value readable

Mono

Set mono for account numbers, IBANs and addresses. Pass the raw string as value and a grouped version as displayValue, so people read groups and paste digits.

IBANGB29 NWBK 6016 1331 9268 19
Wallet address0x71C7656EC7ab88b098defB751B7401B5f6d8976F
import { CopyField } from "@/components/ui/copy-field"

export function CopyFieldMono() {

Masked

Set masked to hide card numbers and security codes. All but the last visibleChars characters turn into dots, spacing is kept, and the copy button still writes the full value. Use visibleChars={0} to hide the whole value, for example a CVC.

Card numberHidden, ending in 4242
CVCHidden
import { CopyField } from "@/components/ui/copy-field"

export function CopyFieldMasked() {

Large

Use size="lg" for verification and pairing codes that people copy or type on another device. Add mono for codes with letters.

Verification code482 913
Pairing codeK7QM-2XRP
import { CopyField } from "@/components/ui/copy-field"

export function CopyFieldLarge() {

Hidden label

Set hideLabel when a heading or line of text above already says what the value is. The label stays available to screen readers and still names the copy button.

Enter this code on your other device

Pairing codeK7QM-2XRP
import { CopyField } from "@/components/ui/copy-field"

export function CopyFieldHiddenLabel() {

Disabled

Set isDisabled when the value can no longer be copied, such as a number that is no longer linked to the account. The button is disabled and the value turns muted but stays readable.

Phone number+1 415 555 0132
Verification code482 913
import { CopyField } from "@/components/ui/copy-field"

export function CopyFieldDisabled() {

Copy callback

Use onCopy to react after a successful copy, for example to log that a link was copied. Change the button verb with copyLabel, for example when you translate the UI.

Payment linkhttps://example.com/pay/8F3K2Q

Not copied yet

"use client"

import * as React from "react"

Accessibility

The copy button is a React Aria Button, so it works with mouse, touch and keyboard. Its accessible name is built from copyLabel and label, for example "Copy routing number". Acronyms such as "IBAN" keep their case.

  • Always pass a label that says what the value is. It names both the value and the button, even with hideLabel.
  • After each attempt a polite live region says "Copied" or "Couldn't copy". It speaks again on repeated copies.
  • When masked is set, the dots are hidden from screen readers and replaced with "Hidden, ending in 4242", so the secret is never read aloud.
  • If the clipboard API is missing or the write is rejected, the field shows the failed state instead of failing silently.

API Reference

CopyField

One copyable value with its label. Accepts all div props except children and onCopy.

PropTypeDefaultDescription
labelstring-Required. What the value is, e.g. "Card number". Also names the copy button.
valuestring-Required. The exact string written to the clipboard.
displayValuestring-What to show instead of the raw value, e.g. a grouped card number.
monobooleanfalseMonospace, tabular digits. Long values wrap at any character.
maskedbooleanfalseHide all but the last characters of what is shown. Copy still writes the real value.
visibleCharsnumber4How many trailing characters stay visible when masked. 0 hides the whole value.
onCopy(value: string) => void-Called with the copied value after a successful copy.
copyLabelstring"Copy"Verb for the copy button. The label is appended, e.g. "Copy card number".
hideLabelbooleanfalseKeep the label for screen readers only.
isDisabledbooleanfalseDisable the button and mute the value.
size"default" | "lg""default""lg" shows the value large with tabular digits, for codes.
classNamestring-Additional classes to apply to the root element.