Agent docs

CopyButton

The one-click copy control that acknowledges itself.

The one-click "copy this value" control that acknowledges itself: click copies, the icon swaps to a checkmark, the tooltip flips to "Copied!", and both revert after a moment. Built entirely on Button (copy-button.tsx:74-91), not a second button implementation; see button.md for every prop it forwards.

The canon behind it. docs/design-language/10-overlays.md §A12 (10-overlays.md:56, copy belongs on values that name the thing, never on values reporting how work is going) and docs/design-language/02-buttons-and-actions.md §A8 (02-buttons-and-actions.md:40, icons come from the shared registry, never a callsite import).

When to reach for it#

Anywhere a value needs a clipboard affordance: an id, a SKU, a generated payload, a table cell. It is described in the source as the single highest-reuse micro-interaction in a data-heavy app (copy-button.tsx:33-36), and the kit's own Table composes it internally for copyCells (table.tsx:371-376), so any table with that feature on is already shipping one per data cell.

Contract#

  • value: the exact text placed on the clipboard.
  • children: optional label beside the icon. Omit it for an icon-only button; circle then defaults to true (circle ?? children == null, copy-button.tsx:79).
  • copyLabel / copiedLabel: the tooltip (and, when children is given, the visible label) before and after a successful copy. Default "Copy" / "Copied!".
  • timeout: how long the checkmark/"Copied!" acknowledgement lasts, in ms. Default 1200.
  • onCopied(value): value-first, fires after a successful write, described in the type doc as "the place to also toast" (copy-button.types.ts:21).
  • size / variant / color / circle / iconSize / disabled / shade / tooltipProps: passed straight through to the underlying Button (Pick<ButtonProps, ...>, copy-button.types.ts:10-13). Default size="sm" variant="ghost" color="neutral". While the acknowledgement is showing, the button's color is forced to "success" regardless of the color prop (copy-button.tsx:78).
  • Icon: the idle glyph, for when the thing copied is not "text" (a prompt, a link). Default "Copy"; the checkmark still replaces it after a copy.
  • tooltipProps is how an icon-only copy button gets the rich two-line tip (tooltip.md, "The rich preset"): tooltipProps={{ title: "Copy path" }} puts the label the icon replaced above the copyLabel body, and the title stays through the "Copied!" acknowledgement. When the title is a string it is also the button's accessible name, ahead of copyLabel (copy-button.tsx:76-80).
  • Slot classnames per CopyButtonClassNames: className the button, _className the Tooltip wrapper, iconClassName the icon.

Mechanics#

Writing to the clipboard prefers navigator.clipboard.writeText, falling back to a hidden off-screen <textarea> plus document.execCommand("copy") for insecure contexts or older browsers (copy-button.tsx:7-30). The click handler calls event.stopPropagation() first, because a copy button commonly sits inside a clickable row or card and must never also trigger that row's own click (copy-button.tsx:62-63).

Sanctioned combinations#

CombinationProducesWhere usedWhy
No children, default circleAn icon-only copy button beside a mono idwalmart-mvp/frontend/src/components/JobNameCell.tsx:43, speedway/app/routes/admin/scrape-requests.tsx:176-181The id text is already visible next to it; the button only needs to act, not re-label the value
variant="text" circle, wrapped in a parent with opacity-0 group-hover:opacity-100A copy control that only appears on row/definition hoverwalmart-mvp/frontend/src/features/parts/PartPreviewModal.tsx:93-99Keeps a dense key/value list quiet until the reader's cursor is actually there
size="xs" variant="ghost" iconSize={12}, composed inside a cell's own hover-reveal wrapperThe table copyCells per-cell copy affordancetable.tsx:371-376, consumed by every table with copyCells on (table.md, 14+ call sites)The kit's own reference implementation of the hover-reveal pattern above
No children, variant="text", Icon="Contract", tooltipProps={{ title: "Copy prompt" }}An icon-only header action with a two-line tip: the label above, what it does belowapps/playground/src/app/showcase-title.tsx:55-64 (every showcase page's Copy prompt and Copy path)The icon replaced the label, so the tip carries the label as its title and the help as its body; the reader never has to guess what a circle does

Banned combinations#

None found; there is nothing shipped that misuses this component. One naming collision is worth knowing about: walmart-mvp/frontend/src/features/catalog/WalmartSubmit.tsx:511 declares its own local CopyButton function, unrelated to the kit's, for a listing title bar's copy control (WalmartSubmit.tsx:479). Check the import, @versable-git/ui versus a local declaration, before reading or extending a CopyButton call site in that file.

Before you adopt this#

Five questions to answer before reaching for CopyButton.

  1. Does the shell, a parent layout, or a global provider already render this? Not applicable, CopyButton is a local control; no shell already renders it.
  2. Does this app already ship a local implementation of the same thing? Walmart's WalmartSubmit.tsx declares its own unrelated local CopyButton; check the import.
  3. Does this app's kit pin reach the version this component or prop landed in? Not applicable, no version-landed CopyButton prop is noted in this doc.
  4. Does the component derive its own accessible name and keyboard path, or must the call site supply them? tooltipProps.title doubles as the aria-label when there is no visible children.
  5. Which canon §A rules bind this surface, and which does the composition break? §A12 reserves copy for values naming the thing, never status.

Travels with#

  • Button, which it wraps entirely; every appearance prop is Button's own.
  • Tooltip, via Button's own unconditional tooltip wrapper.

Snippet#

// walmart-mvp/frontend/src/components/JobNameCell.tsx:43
<CopyButton value={jobName} size="xs" variant="ghost" iconSize={12} copyLabel="Copy job name" />
@versable-git/ui · reference, canon, and method, read in place