Rocket Copy Button Pro

Rocket is currently in beta.

Demo

A simple, reusable copy-to-clipboard button component with visual feedback.

Explanation #

The demo page owns the editable text and passes it to the component as a prop. The component keeps only its ephemeral copied state in setup() so it can show feedback and clear the timeout.

Usage Example #

1<div data-signals='{"myCode":"To infinity and beyond"}'>
2    <input data-bind:my-code type="text" />
3    <copy-button data-attr:code="$myCode"></copy-button>
4</div>

Rocket Component #

 1import { rocket } from 'datastar'
 2
 3rocket('copy-button', {
 4  mode: 'light',
 5  props: ({ string }) => ({
 6    code: string,
 7  }),
 8  setup: ({ $$, cleanup, host, props }) => {
 9    $$.copied = false
10    let timer = 0
11
12    host.addEventListener('click', onClick)
13
14    cleanup(() => {
15      clearTimeout(timer)
16      host.removeEventListener('click', onClick)
17    })
18
19    async function onClick(evt) {
20      if (!(evt.target instanceof Element)) return
21      if (!evt.target.closest('button.copy-button')) return
22      await navigator.clipboard.writeText(props.code ?? '')
23      $$.copied = true
24      clearTimeout(timer)
25      timer = setTimeout(() => {
26        $$.copied = false
27      }, 2000)
28    }
29  },
30  render: ({ html }) => html`
31    <div class="copy-button-wrapper">
32      <button
33        class="copy-button small"
34        type="button"
35        title="Copy code"
36      >
37        <iconify-icon
38          noobserver
39          data-attr:icon="'pixelarticons:' + ($$copied ? 'section-copy' : 'copy')"
40        ></iconify-icon>
41      </button>
42      <span data-show="$$copied" class="copy-popover">Copied!</span>
43    </div>
44  `,
45})