Clipboard
stimeo--clipboard
Copies text and reports whether it worked, in writing and out loud.
Copies the text you point it at, using the browser's own clipboard, with no extra dependency. Whether it worked is shown in a visible slot and announced through the shared announcer, never left to a changing icon alone. The result clears itself after a moment, and it is not left behind when you leave the page and come back.
Keyboard
| Key | Action |
|---|---|
| Enter / Space | Activate the copy button (native button). |
<%# Markup for the clipboard (copy & completion feedback) demo.
Copies via navigator.clipboard, shows the result in the visible feedback slot,
and hands the announcement to the shared stimeo--announcer your app seats once,
in its layout. Keep the feedback slot free of live-region semantics — the
announcer already reads the result, so a role="status" here would say it twice.
For localization the visible labels come from the copied-label / error-label
Values and the spoken ones from the announce-copied-text / announce-error-text
Values. The look per data-state (idle / copied / error) lives in demo.css. %>
<div
class="clipboard"
data-controller="stimeo--clipboard"
data-stimeo--clipboard-feedback-duration-value="2000"
data-stimeo--clipboard-copied-label-value="<%= t('components.clipboard.demo.copied') %>"
data-stimeo--clipboard-error-label-value="<%= t('components.clipboard.demo.error') %>"
data-stimeo--clipboard-announce-copied-text-value="<%= t(
'components.clipboard.demo.announce_copied'
) %>"
data-stimeo--clipboard-announce-error-text-value="<%= t(
'components.clipboard.demo.announce_error'
) %>">
<input
class="clipboard__source"
type="text"
readonly
aria-label="<%= t('components.clipboard.demo.source_label') %>"
value="https://stimeo.example/share/abc123"
data-stimeo--clipboard-target="source">
<button
class="clipboard__button"
type="button"
data-stimeo--clipboard-target="button"
data-action="click->stimeo--clipboard#copy">
<%= t("components.clipboard.demo.button") %>
</button>
<span class="clipboard__feedback" data-stimeo--clipboard-target="feedback"></span>
</div>
/*
* Presentation-only styles for the clipboard demo.
* Success / failure styling switches on the data-state the library sets on the
* controller element. The feedback slot is a plain visible label — the shared
* announcer does the reading, so it needs no live-region styling of its own.
*/
.clipboard {
display: flex;
align-items: center;
gap: 0.5rem;
flex-wrap: wrap;
max-width: 32rem;
}
.clipboard__source {
flex: 1 1 16rem;
padding: 0.5rem 0.75rem;
border: 1px solid var(--border-strong);
border-radius: 0.375rem;
font: inherit;
color: var(--fg);
background: var(--surface-subtle);
}
.clipboard__button {
padding: 0.5rem 0.9rem;
border: 1px solid var(--accent-fill);
border-radius: 0.375rem;
/* White needs the 700 step behind it: the brand accent (vital-500) measures
2.99:1 under white, a body-size AA failure. The fill token clears it in both. */
background: var(--accent-fill);
color: var(--white);
font: inherit;
font-weight: 600;
cursor: pointer;
}
.clipboard[data-state="copied"] .clipboard__button {
background: var(--leaf-500);
border-color: var(--leaf-500);
}
.clipboard[data-state="error"] .clipboard__button {
background: var(--danger-500);
border-color: var(--danger-500);
}
.clipboard__feedback {
flex-basis: 100%;
min-height: 1.25rem;
font-size: 0.875rem;
color: var(--leaf-500);
}
.clipboard[data-state="error"] .clipboard__feedback {
color: var(--danger-500);
}
// Consumer-side JS for the clipboard demo (optional).
// The library fires stimeo--clipboard:copy on every copy attempt with
// detail { success, text }. The consumer subscribes to add its own behavior
// (analytics, a toast, etc.) — here just a simple log.
document.addEventListener("stimeo--clipboard:copy", (event) => {
const { success, text } = event.detail;
console.log(`[clipboard] success=${success} text=${text}`);
});
These demo styles use shared design tokens (light + dark). Copy the shared styles too, then toggle data-theme on your root element for dark mode.
The data-* attributes you add to your own HTML to wire this component. Put the data-controller below on a root element, then place its targets / values / actions inside that element.
On the root element
data-controller="stimeo--clipboard"
Targets
| Name | Description | Attribute |
|---|---|---|
source
|
The element whose value or text content is copied when no explicit text value is set. |
data-stimeo--clipboard-target="source" |
button
required
|
The button that triggers the copy action. | data-stimeo--clipboard-target="button" |
feedback
|
The visible slot that shows the copied or error label. Do not give it live-region semantics — the shared announcer already reads the result. | data-stimeo--clipboard-target="feedback" |
Values
| Name | Description | Attribute |
|---|---|---|
text
|
Explicit text to copy; when empty (default), the source target's value or text is used instead. | data-stimeo--clipboard-text-value |
feedbackDuration
|
Milliseconds before the completion state auto-clears and returns to idle (default 2000); 0 or less arms no timer, so it stands until the next copy — a reconnect and the before-cache rewind still clear it. | data-stimeo--clipboard-feedback-duration-value |
copiedLabel
|
Label shown in the feedback slot on a successful copy (default "Copied"). | data-stimeo--clipboard-copied-label-value |
errorLabel
|
Label shown in the feedback slot when the copy fails (default "Copy failed"). | data-stimeo--clipboard-error-label-value |
announceCopiedText
|
Message sent to the shared announcer on a successful copy; empty (default) announces nothing. | data-stimeo--clipboard-announce-copied-text-value |
announceErrorText
|
Message sent to the shared announcer when the copy fails; empty (default) announces nothing. | data-stimeo--clipboard-announce-error-text-value |
Actions
| Name | Description | Action |
|---|---|---|
copy
|
Copies the resolved text to the clipboard, reflects the outcome on data-state, shows the feedback message, and announces it. |
stimeo--clipboard#copy |
Events
| Name | Description | Event |
|---|---|---|
copy
|
Dispatched after every copy attempt with { success, text } in detail, including on failure. |
stimeo--clipboard:copy |
State hooks
The library only manages these ARIA/data attributes and custom properties. Your CSS reads them to render the look — selectors like [aria-selected], [aria-expanded], or var(--stimeo--…) hook into this state.
| Hook | Target | Meaning |
|---|---|---|
data-state |
Root element | "idle" / "copied" / "error". The last two are transient and return to idle on reconnect. |
text content |
Feedback | The visible completion or failure message (not a live region). |