Copy-to-clipboard buttons: an accessibility checklist
Why this matters
“Copy” is a high-frequency action. When the feedback is only a toast that isn’t announced, or when the control isn’t keyboard-operable, people lose confidence and repeat the action (often copying the wrong thing).
Checklist
- Use a real control: prefer
<button type="button">, not a clickable<div>/<span>. - Label the action: “Copy invite code” is better than “Copy”. If multiple copy buttons exist, labels must be unique.
- Make the copied value visible: show the exact value near the button (or provide an adjacent read-only field).
- Require a user gesture: browsers generally block clipboard writes without a click/tap/keypress.
- Announce outcomes: provide a short status message using
role="status"andaria-live="polite". Keep the message brief so it doesn’t interrupt other announcements. - Handle failure: if copy fails, instruct the user how to copy manually (select + copy) and don’t claim success.
- Don’t steal focus: after copy, keep focus on the button. Don’t auto-select text unless the user asked for it.
- Offer a fallback: try the Clipboard API first, and optionally a best-effort legacy fallback (with a clear failure message if it doesn’t work).
- Be careful with secrets: avoid “Copy API key” patterns that put sensitive data into the clipboard without clear warnings.
Minimal example
<label for="invite">Invite code</label>
<input id="invite" value="RIVER-INDIGO-7H2Q" readonly>
<button type="button" id="copy" aria-describedby="copyStatus">
Copy invite code
</button>
<span id="copyStatus" role="status" aria-live="polite" aria-atomic="true"></span>
<script>
const input = document.getElementById('invite');
const status = document.getElementById('copyStatus');
document.getElementById('copy').addEventListener('click', async () => {
status.textContent = '';
try {
await navigator.clipboard.writeText(input.value);
status.textContent = 'Copied.';
} catch {
status.textContent = 'Copy failed. Select the value and copy manually.';
}
});
</script>
Common pitfalls
- Alert-only feedback: browser alerts are disruptive and often blocked; they also don’t scale to repeated actions.
- Tooltip-only feedback: many tooltips aren’t announced to screen readers (and can be missed by keyboard users).
- Multiple live regions: avoid triggering several announcements at once (e.g., toast + inline + aria-live).
- Auto-copy on page load: blocked by browsers, and it surprises users.