Deck
Browse the catalog

Build / Molecules

CopyField

  • molecule
  • play-fn

A read-only value with a one-click copy — a shareable link, an API key, an invite code.

The value is a real readOnly input rather than plain text, so it stays selectable and copyable by hand as a fallback when navigator.clipboard is unavailable or denied.

import { CopyField } from '@meetcard/deck'

Example

<CopyField label="Shareable link" value="meetcard.io/ben" icon={<LinkIcon />} />

Stories

Every preview below is the real component, rendered in this page from the same story Storybook runs. The width control resizes each preview's container; CSS media queries still follow the browser window, so breakpoint behaviour is worth checking in Storybook.

Default
Source
const Default = () => <CopyField
    label="Shareable link"
    value="meetcard.io/ben@meetcard"
    icon={<LinkIcon />} />;

Label shown, for a field on a form rather than on its own in a sheet.

Visible Label
Source
const VisibleLabel = () => <CopyField
    label="Shareable link"
    value="meetcard.io/ben@meetcard"
    icon={<LinkIcon />}
    showLabel />;

No icon, where the surrounding copy already says what the value is.

Without Icon
Source
const WithoutIcon = () => <CopyField label="Shareable link" value="meetcard.io/ben@meetcard" icon={undefined} />;

The button swaps to a checkmark once the value is copied, then swaps back. Clipboard write permission isn't reliably grantable in a headless browser, so the write itself is stubbed — the point under test is the component's own state, not whether Chromium will hand out the clipboard.

Copy Interaction
Source
const CopyInteraction = () => <CopyField
    label="Shareable link"
    value="meetcard.io/ben@meetcard"
    icon={<LinkIcon />} />;

A denied clipboard is the expected case on an insecure origin, so it must not throw — the value stays selectable in the input as a manual fallback.

Copy Denied
Source
const CopyDenied = () => <CopyField
    label="Shareable link"
    value="meetcard.io/ben@meetcard"
    icon={<LinkIcon />} />;

Focusing selects the whole value. The field is read-only and exists to be taken somewhere else, so a click should not leave a caret mid-string.

Focus Selects The Value
Source
const FocusSelectsTheValue = () => <CopyField
    label="Shareable link"
    value="meetcard.io/ben@meetcard"
    icon={<LinkIcon />} />;

Props

PropTypeDefaultDescription
labelrequiredReactNode—Accessible name for the field.
valuerequiredstring——
classNamestring——
copyLabelstring'Copy link'Accessible name for the copy control, before a copy succeeds.
iconReactNode—Decorative leading icon, e.g. a link glyph.
idstring——
showLabelbooleanfalseShow the label above the field instead of only to assistive tech.
size'sm' | 'md' | 'lg''md'—

Open in Storybookfor controls, the a11y panel and the interaction runner.