Copy Button — <mv-copy-button>
Copy button with odometer feedback: icon and label roll up to a check (or drop down to an alert on failure) inside fixed windows, while a tinted wash fills the button and drains over the timeout as a countdown; icon buttons get a status tag.
Category Micro-interactions Type Web Component (<mv-copy-button>) Status stable Keywords copy, clipboard, roll, odometer, success, feedback, code
When to use
A code block, API key or share link needs a copy button with clear success or failure feedback An icon-only copy control in a toolbar or command bar should show a status tag and a timed reset A copied state should visibly count down before the button returns to idle
Avoid when
The button toggles an on/off state rather than performing a one-shot copy → use Toggle instead
Get Copy Button. Included in every plan: the Pro pack ships all 226 components with the CLI and the MCP server used below.
See plans
Install
node scripts/add.mjs copy-button --out ./src/marvelous
AI agent with the Marvelous UI MCP server: install_components({ slugs: ["copy-button"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Files copied (dependencies included): tokens/tokens.css, core/base.css, core/element.js, core/motion.js, components/copy-button/copy-button.js, components/copy-button/copy-button.css.
Usage
Canonical markup — start from it and customize with attributes, data-* and CSS variables:
<div style="display:grid;gap:1rem;width:100%;max-width:520px">
<div style="display:flex;align-items:center;gap:.5rem;padding:.4rem .4rem .4rem .9rem;border:1px solid var(--mv-border);border-radius:var(--mv-radius-lg);background:var(--mv-bg-subtle);font:500 .85rem/1 var(--mv-font-mono)">
<span style="color:var(--mv-fg-subtle)">$</span>
<code style="flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">node scripts/add.mjs confetti</code>
<mv-copy-button value="node scripts/add.mjs confetti" data-variant="ghost" label="Copy command"></mv-copy-button>
</div>
<div style="position:relative;border:1px solid var(--mv-border);border-radius:var(--mv-radius-lg);background:var(--mv-surface);overflow:hidden">
<div style="display:flex;justify-content:space-between;align-items:center;padding:.4rem .5rem .4rem .9rem;border-bottom:1px solid var(--mv-border);font-size:.75rem;color:var(--mv-fg-muted)">
<span>index.html</span>
<mv-copy-button target="#mv-copy-demo-code">Copy code</mv-copy-button>
</div>
<pre style="margin:0;padding:.85rem 1rem;font:.8rem/1.6 var(--mv-font-mono);overflow:auto"><code id="mv-copy-demo-code"><mv-like count="128"></mv-like>
<script type="module" src="like-button.js"></script></code></pre>
</div>
<div style="display:flex;flex-wrap:wrap;gap:.6rem;align-items:center">
<input class="mv-input" id="mv-copy-demo-link" value="https://lumen.studio/invite/7QX2" readonly style="flex:1;min-width:200px">
<mv-copy-button target="#mv-copy-demo-link" success-label="Link copied">
<button class="mv-button" data-variant="outline">Copy link</button>
</mv-copy-button>
<mv-copy-button target="#mv-copy-demo-introuvable" label="Copy (missing target: error state)"></mv-copy-button>
</div>
</div>
API
Attributes
Name Type Default Description valuestring Text to copy. targetCSS selector Otherwise: copies the value (field) or the text of the targeted element. labelstring CopyAccessible name of the icon button. success-labelstring Copied!Label / bubble / announcement on success. error-labelstring Copy failedSame, on failure. timeoutnumber 2000Duration of the copied / error state (ms). disabledboolean Disables the button. data-variantghost No border or background (command bars, code blocks). data-bubblebottom Bubble below the button instead of above. data-stateidle | copied | error Set by the component (for styling).
Properties
Name Type Description textstring Text that will be copied (read-only).
Methods
Name Description copy()Copies and plays the feedback; Promise<boolean>.
Events
Name Description mv-copySuccess; detail = { text }. mv-copy-errorFailure; detail = { error }.
Content structure
Name Description (text)Visible label; without text, an icon button with a bubble. buttonOr your own child <button> (e.g. .mv-button): the icon and cross-fade are injected into it.
CSS classes
Name Description mv-copy-button-trigger / -icons / -reel / -slot / -label / -text / -wash / -bubbleGenerated parts (the wash and reel are aria-hidden).
CSS variables
Name Default Description --mv-copy-button-successvar(--mv-success)Check color. --mv-copy-button-errorvar(--mv-danger)Error color. --mv-copy-button-icon-size1.2emIcon size.
Accessibility
A real <button>; the icon button gets an aria-label (“Copy”). The result is announced by a polite role=status region (“Copied!” / “Copy failed”); alternate labels, icons, wash and tag are aria-hidden to avoid duplicates. Clipboard API with an execCommand fallback (insecure contexts); repeated copies restart the timer. Reduced motion: no roll or drain, the state swaps instantly and the tint stays static until reset.