A web component for copying items to the clipboard.
npm install --save @parsonic/copy-to-clipboard
Use copy-to-clipboard with your favourite bundler or directly from a CDN. A
minified build is provided as min.js
with a source map.
Add a script tag with the minified build and use the element in your page.
<script
defer
src="https://cdn.jsdelivr.net/npm/@parsonic/copy-to-clipboard/min.js"></script>
<copy-to-clipboard>
<pre><code>npm install --save @parsonic/copy-to-clipboard</code></pre>
</copy-to-clipboard>
Import the CopyToClipboard
component at the root of your application and
register it.
import CopyToClipboard from '@parsonic/copy-to-clipboard/CopyToClipboard.js'
CopyToClipboard.register()
// Use <copy-to-clipboard></copy-to-clipboard> in your page or components
Import the CopyToClipboard
component from the CDN and register it before
using.
<script type="module">
import CopyToClipboard from 'https://cdn.jsdelivr.net/npm/@parsonic/copy-to-clipboard/CopyToClipboard.js'
CopyToClipboard.register()
</script>
<copy-to-clipboard>
<!-- Content to copy -->
</copy-to-clipboard>
If you prefer to give the element an alternative tag name you can pass this to the register method.
// To use as <my-copy-to-clipboard></my-copy-to-clipboard>
CopyToClipboard.register('my-copy-to-clipboard')
The text content of the element will be copied to the clipboard when the copy button is pressed unless the clipboard item is explicitly set.
<copy-to-clipboard>
<p>This text will be copied to the clipboard</p>
</copy-to-clipboard>
To better format the text either pass the text content to the data-text
attribute on the element or set it using the item
property on the underlying
object. This property is useful when using the element with a JavaScript
framework like React.
<copy-to-clipboard data-text="This is the text copied to the clipboard">
<!-- Page content -->
</copy-to-clipboard>
const copyToClipboard = document.querySelector('copy-to-clipboard')
copyToClipboard.item = new ClipboardItem({
'text/plain': formattedText,
})
To copy other data types like an image to the clipboard pass the URL to the data
in the data-url
attribute. The URL may point to a separate file or contain the
data directly as a data URL.
<copy-to-clipboard data-url="./my-image-full.png">
<img src="./my-image.png" />
</copy-to-clipboard>
<copy-to-clipboard data-url="data:image/png;...">
<img src="./my-image.png" />
</copy-to-clipboard>
As with text the item property of the underlying object can be used for other data types.
// Copy blob to clipboard if type is supported
if (ClipboardItem.supports(blob.type)) {
const copyToClipboard = document.querySelector('copy-to-clipboard')
copyToClipboard.item = new ClipboardItem({
[blob.type]: blob,
})
}
The default button comprises of a button element with two SVG icons, the
clipboard icon and the done icon. When the button is pressed an animation is
applied to the icons to briefly show the done icon as a visual indicator that
the copy was successful. A default ARIA label of Copy
is applied to the button
that can be set using the data-button-label
attribute.
<copy-to-clipboard
data-button-label="Copy image to clipboard"></copy-to-clipboard>
The button can be replaced entirely using the slot named button
or styled. via
the button
CSS part.
<copy-to-clipboard>
<pre>Text to copy...</pre>
<button slot="button">Copy</button>
</copy-to-clipboard>
To style the icons inside the button use the copy-icon
and done-icon
CSS
parts to target the SVG elements.
copy-to-clipboard::part(done-icon) {
stroke: lightgreen;
}
To replace the icons use the copy-icon
and done-icon
slots.
<copy-to-clipboard>
<pre>...</pre>
<svg
slot="copy-icon"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round">
<rect width="14" height="14" x="8" y="8" rx="2" ry="2" />
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2" />
</svg>
</copy-to-clipboard>
The button may also be styled using the CSS custom properties listed below.
:root {
--ctc-button-background: rgb(255 255 255 / 8%);
--ctc-button-border: none;
--ctc-button-color: inherit;
--ctc-button-icon-size: 1rem;
--ctc-button-inset: 0.5rem 0.5rem auto auto;
--ctc-button-padding: 0.5rem;
--ctc-button-radius: 0.5rem;
}
A successful copy will be announced to screen readers by updating a live region
in the copy button with a message. To override the default announcement of
'Copied!', supply a message in the data-announcement
attribute.
<copy-to-clipboard
data-announcement="Text copied to clipboard!"></copy-to-clipboard>
The announcement text is visually hidden by default, to style the text use the
announcement
and button-wrapper
CSS parts.
copy-to-clipboard {
&::part(button-wrapper) {
align-items: center;
display: flex;
flex-flow: row-reverse;
gap: 0.25rem;
}
&::part(announcement) {
height: unset;
position: unset;
width: unset;
}
}
When the copy button is pressed the element dispatches a ClipboardEvent
of
type copy
. The event is set to bubble and is cancellable and contains the
clipboardData
data transfer object. An event handler may set plain text data
to be copied on the data transfer.
<copy-to-clipboard>
<label for="field">A form field</label>
<textarea id="field">Some text to copy</textarea>
</copy-to-clipboard>
<script>
document.addEventListener('copy', (ev) => {
const fieldValue = ev.target.querySelector('textarea').value
ev.clipboardData.setData('text/plain', fieldValue)
})
</script>
Once the item is written to the clipboard the element dispatches a copyResult
custom event. If successful the event detail has a result
of 'success'
and
contains the ClipboardItem
as data
. If an error occurred the result
will
be 'error'
and the error
is provided.
document.querySelector('copyResult', (ev) => {
if (ev.detail.result === 'success') {
console.log('Item copied to ciipbard', ev.detail.data)
} else {
console.error('Failed to copy', ev.detail.error)
}
})