@svelte-put/copy
Installation
npm install --save-dev @svelte-put/copy
pnpm add -D @svelte-put/copy
yarn add -D @svelte-put/copy
Minimal Usage
By default, copy
will trigger a click
1 event listener on the same node 2 it is used on. The triggered listener will then copy innerText of said node 3 to the default clipboard. The next sections show how 1, 2, 3 can be customized.
Below is a minimal demo of copy
with default options. Try clicking on the green button to observe the text within being copied to the blue box.
<script lang="ts">
import { copy, type CopyDetail } from '@svelte-put/copy';
import { fade } from 'svelte/transition';
let copied = '';
function handleCopied(e: CustomEvent<CopyDetail>) {
copied = e.detail.text;
}
</script>
<div class="not-prose grid grid-cols-[1fr,auto,1fr] items-center gap-2">
<button
class="bg-green-500 p-2 active:scale-95"
type="button"
use:copy
on:copied={handleCopied}
>
<strong class="text-blue-500">Click</strong> <span class="text-black">to copy this</span>
</button>
<div>-></div>
<div class="grid place-items-center self-stretch bg-blue-200 text-black">
{#if copied}
<p in:fade={{ duration: 200 }}>
{copied}
</p>
{/if}
</div>
</div>
1 Customizing the Event Types
Pass one or more event types to the event
option.
<script>
import { copy } from '@svelte-put/copy';
</script>
<button type="button" use:copy={{ event: 'mousedown' }}>...</button>
<button type="button" use:copy={{ event: ['pointerenter', 'pointerleave'] }}>...</button>
2 Customizing the Trigger
The trigger
option, which typically takes an HTMLElement
, specifies the node to which the event listener is attached.
The copy button seen in code blocks on this site is powered by this very action.
A typical use case is clicking on a node to copy text within some other node. In the demo below, try clicking on the green button to copy text in the yellow-bordered box.
<script lang="ts">
import { copy, type CopyDetail } from '@svelte-put/copy';
import { fade } from 'svelte/transition';
let trigger: HTMLButtonElement;
let copied = '';
function handleCopied(e: CustomEvent<CopyDetail>) {
copied = e.detail.text;
}
</script>
<div class="not-prose grid grid-cols-[0.5fr,auto,0.5fr,auto,1fr] items-center gap-4">
<button class="bg-green-500 p-2 text-black active:scale-95" type="button" bind:this={trigger}>
Click
</button>
<div>to</div>
<div
class="grid place-items-center border border-yellow-500 p-2"
use:copy={{ trigger }}
on:copied={handleCopied}
>
<p>copy this</p>
</div>
<div>-></div>
<div class="grid place-items-center self-stretch bg-blue-200 text-black">
{#if copied}
<p in:fade={{ duration: 200 }}>
{copied}
</p>
{/if}
</div>
</div>
3 Customizing How Text is Copied
The text
option can receive a literal string or a sync/async callback that returns a string, which if provided, will be used for copying instead of the default innerText
attribute of the node the action is placed on.
Literal
<button use:copy={{ text: 'some static text' }}>Copy me</button>
Callback
Here, text
is a callback; its parameter contains information about the forwarded event, reference to node
(on which the action is placed), and the trigger
(to which event is attached).
<script lang="ts">
import { copy, type TextResolverInput } from '@svelte-put/copy';
import { fade } from 'svelte/transition';
let copied = '';
function copyText(input: TextResolverInput<'pointerdown'>) {
const { node } = input;
copied = `Custom - ${node.innerText}`;
return copied;
}
</script>
<div class="not-prose grid grid-cols-[1fr,auto,1fr] items-center gap-2">
<button
class="bg-green-500 p-2 text-black active:scale-95"
type="button"
use:copy={{ event: 'pointerdown', text: copyText }}
>
Click
</button>
<div>-></div>
<div class="grid place-items-center self-stretch bg-blue-200 text-black">
{#if copied}
<p in:fade={{ duration: 200 }}>
{copied}
</p>
{/if}
</div>
</div>
copy
Event
Simulating the If the synthetic
option is set to true
, a “fake” copy event will be dispatched alongside the copied
CustomEvent, should that be of any use.
Note that since this synthetic copy
event is not “real”, operations on clipboardData will have no effect on the actual copied text.
<script lang="ts">
import { copy } from '@svelte-put/copy';
import { fade } from 'svelte/transition';
let copied = '';
function onSyntheticCopy(e: ClipboardEvent) {
const clipboardData = e.clipboardData;
copied = clipboardData?.getData('text/plain') ?? '';
// clipboardData.setData will have no effect here
}
</script>
<div class="not-prose grid grid-cols-[1fr,auto,1fr] items-center gap-2">
<button
class="bg-green-500 p-2 active:scale-95"
type="button"
use:copy={{ synthetic: true }}
on:copy={onSyntheticCopy}
>
<strong class="text-blue-500">Click</strong> <span class="text-black">synthetic copy</span>
</button>
<div>-></div>
<div class="grid place-items-center self-stretch bg-blue-200 text-black">
{#if copied}
<p in:fade={{ duration: 200 }}>
{copied}
</p>
{/if}
</div>
</div>
copyToClipboard
Helper
The Behind the scene, copy
uses a copyToClipboard
helper (See its source code here). You may skip the action and use this utility directly to build your own custom solution that fits your exact need.
import { copyToClipboard } from '@svelte-put/copy';
export function customCopy(text: string) {
copyToClipboard(text);
}
Happy copying! 👨💻