use-clipboard-copy
Version:
Lightweight copy to clipboard hook for React
303 lines (222 loc) • 10.3 kB
Markdown
<h1 align="center">
<img src="https://user-images.githubusercontent.com/2100222/55596467-9c054980-5716-11e9-8723-b8c286fcd9e3.png" width="128">
<br>
use-clipboard-copy
</h1>
<p align="center">
<a href="https://www.npmjs.com/package/use-clipboard-copy">
<img src="https://img.shields.io/npm/v/use-clipboard-copy.svg" alt="Current Release" />
</a>
<a href="https://www.npmjs.com/package/use-clipboard-copy">
<img src="https://badgen.net/npm/dt/use-clipboard-copy" alt="Downloads" />
</a>
<a href="https://travis-ci.org/wsmd/use-clipboard-copy">
<img src="https://travis-ci.org/wsmd/use-clipboard-copy.svg?branch=master" alt="CI Build">
</a>
<a href='https://coveralls.io/github/wsmd/use-clipboard-copy?branch=master'>
<img src='https://coveralls.io/repos/github/wsmd/use-clipboard-copy/badge.svg?branch=master' alt='Coverage Status' />
</a>
<a href="https://github.com/wsmd/use-clipboard-copy/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/wsmd/use-clipboard-copy.svg" alt="Licence">
</a>
</p>
<details>
<summary>📖 Table of Contents</summary>
<p>
- [Motivation](#motivation)
- [Getting Started](#getting-started)
- [Usage](#usage)
- [Copying Text of Another Target Element](#copying-text-of-another-target-element)
- [Copying Text Imperatively (Without a Target Element)](#copying-text-imperatively-without-a-target-element)
- [Displaying a Temporary Success State](#displaying-a-temporary-success-state)
- [Handling Success and Errors](#handling-success-and-errors)
- [Browser Support](#browser-support)
- [API](#api)
- [`useClipboard(options?: UseClipboardOptions): ClipboardAPI`](#useclipboardoptions-useclipboardoptions-clipboardapi)
- [`UseClipboardOptions`](#useclipboardoptions)
- [`copiedTimeout?: number`](#copiedtimeout-number)
- [`onSuccess?: () => void`](#onsuccess---void)
- [`onError?: () => void`](#onerror---void)
- [`selectOnCopy?: boolean`](#selectoncopy-boolean)
- [`selectOnError?: boolean`](#selectonerror-boolean)
- [`ClipboardAPI`](#clipboardapi)
- [`copy: (text?: string) => void`](#copy-text-string--void)
- [`target: React.RefObject<any>`](#target-reactrefobjectany)
- [`isSupported: () => boolean`](#issupported---boolean)
- [`copied: boolean`](#copied-boolean)
- [Acknowledgements](#acknowledgements)
- [License](#license)
</p>
</details>
## Motivation
There are various copy-to-clipboard solutions for Javascript – really good ones, but getting them to work with React can feel a little odd... they don't feel very _React-y_.
`use-clipboard-copy` is a **lightweight** (< 1KB) React hook that makes it possible to add a copy-to-clipboard functionality to your React application with very little code! A simple implementation looks like this:
```js
function CopyText() {
const clipboard = useClipboard();
return (
<div>
<input ref={clipboard.target} />
<button onClick={clipboard.copy}>Copy</button>
</div>
);
}
```
P.S. You can do more than that with `use-clipboard-copy`. Keep reading!
## Getting Started
To get started, add `use-clipboard-copy` to your project:
```
npm install --save use-clipboard-copy
```
Please note that `use-clipboard-copy` requires `react@^16.8.0` as a peer dependency.
## Usage
### Copying Text of Another Target Element
A simple copy-to-clipboard interface consists of two parts:
- The `target`, an element who holds the value to be copied, usually an input.
- The `copy` action.
```jsx
import { useClipboard } from 'use-clipboard-copy';
export default function PublicUrl({ url }) {
const clipboard = useClipboard();
return (
<div>
<input ref={clipboard.target} value={url} readOnly />
<button onClick={clipboard.copy}>Copy Link</button>
</div>
);
}
```
### Copying Text Imperatively (Without a Target Element)
It is also possible to perform a copy action imperatively (programmatically). For example, a copy-to-clipboard interface may consist of a single copy button without any additional inputs or values displayed to the user. By passing a string to the `clipboard.copy` action, the specified string will be copied to the clipboard.
```jsx
import { useClipboard } from 'use-clipboard-copy';
export default function PublicUrl({ id }) {
const clipboard = useClipboard();
const handleClick = React.useCallback(
() => {
const url = Utils.formatUrl({ query: { id } });
clipboard.copy(url); // programmatically copying a value
},
[clipboard.copy, id]
);
return (
<button onClick={handleClick}>Copy Link</button>
);
}
```
### Displaying a Temporary Success State
Sometimes it can be helpful to notify the user that the text was successfully copied to the clipboard, usually by displaying a temporary "Copied" state after they trigger the copy action.
By passing the `copiedTimeout` option to `useClipboard()`, you can use `clipboard.copied` as a way to toggle the copied state in the UI.
```jsx
import { useClipboard } from 'use-clipboard-copy';
export default function PublicUrl({ url }) {
const clipboard = useClipboard({
copiedTimeout: 600, // timeout duration in milliseconds
});
return (
<div>
<input ref={clipboard.target} value={url} readOnly />
<button onClick={clipboard.copy}>
{clipboard.copied ? 'Copied' : 'Copy Link'}
</button>
</div>
);
}
```
### Handling Success and Errors
Copy to clipboard in browsers can be tricky some times - there are various reasons that can contribute to preventing the copy action from working. Therefore, you should always handle such cases.
By passing an `onSuccess` and `onError` callbacks to the `useClipboard` options, you will be able to handle whether the `copy` action was performed successfully.
```js
function CopyText() {
const clipboard = useClipboard({
onSuccess() {
console.log('Text was copied successfully!')
},
onError() {
console.log('Failed to copy text!')
}
});
return (
<div>
<input ref={clipboard.target} />
<button onClick={clipboard.copy}>Copy</button>
</div>
);
}
```
In case the `copy` action fails, `useClipboard` will handle that gracefully by selecting the `target` input instead so that users can copy the text manually. This behavior can be disabled by passing `selectOnError: false` to the clipboard options.
## Browser Support
`use-clipboard-copy` is supported in all browsers that [supports the native clipboard APIs](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Interact_with_the_clipboard), including major browsers such as **Chrome, Firefox, Edge, Safari, IE11**.
This hook provides an `isSupported` method that you can use to check for browser support and update the UI accordingly:
```jsx
function ClipboardSupport() {
const clipboard = useClipboard();
return (
<div>
{clipboard.isSupported()
? "yay! copy-to-clipboard is supported"
: "meh. copy-to-clipboard is not supported"}
</div>
);
}
```
## API
### `useClipboard(options?: UseClipboardOptions): ClipboardAPI`
`use-clipboard-copy` exposes a named export `useClipboard` which is the hook function itself. It takes an optional options object, and returns an object to control the clipboard.
```js
import { useClipboard } from 'use-clipboard-copy';
function CopyText() {
const clipboard = useClipboard();
return (
// ...
);
}
```
### `UseClipboardOptions`
`useClipboard` takes an optional object with the following properties:
- [`copiedTimeout?: number`](#copiedtimeout-number)
- [`onSuccess?: () => void`](#onsuccess---void)
- [`onError?: () => void`](#onerror---void)
- [`selectOnCopy?: boolean`](#selectoncopy-boolean)
- [`selectOnError?: boolean`](#selectonerror-boolean)
#### `copiedTimeout?: number`
The duration in milliseconds used to toggled the [`copied`](#copied-boolean) state upon a successful copy action.
#### `onSuccess?: () => void`
A callback function that will be called upon a successful copy action.
#### `onError?: () => void`
A callback function that will be called when the copy action fails.
#### `selectOnCopy?: boolean`
Defaults to `false`.
A boolean indicating whether the text of the [`target`](#target-reactrefobjectany) element (if set) will be selected upon a successful copy action.
#### `selectOnError?: boolean`
Defaults to `true`.
A boolean indicating whether the text of the [`target`](#target-reactrefobjectany) element (if set) will be selected when the copy action fails.
### `ClipboardAPI`
`useClipboard` returns an object with the following properties:
- [`copied: boolean`](#copied-boolean)
- [`copy: (text?: string) => void`](#copy-text-string--void)
- [`isSupported: () => boolean`](#issupported---boolean)
- [`target: React.RefObject<any>`](#target-reactrefobjectany)
#### `copy: (text?: string) => void`
A method that will be used to preform the copy action. If it's used without passing a string, the `copy` action will use the text of the [`target`](#target-reactrefobjectany) element (if set).
```jsx
<input ref={clipboard.target} value="a text to copy" />;
<button onClick={clipboard.copy} />;
```
Optionally, `copy` takes a `string` to perform the copy action imperatively (programmatically). When this is used, the [`target`](#target-reactrefobjectany) element (if set) will be ignored.
```jsx
<button onClick={() => clipboard.copy('a text to copy')} />;
```
#### `target: React.RefObject<any>`
A React Ref object used on input and textarea elements that holds the text to be copied.
```jsx
<input ref={clipboard.target} value="a text to copy" />;
```
#### `isSupported: () => boolean`
A function that returns a boolean indicating whether the browser supports the clipboard APIs. Useful to deterministically update the UI if the browser does not support the clipboard functionality for whatever reason.
#### `copied: boolean`
A boolean indicating whether the copy action was just performed. Must be used with the [`copiedTimeout`](#copiedtimeout-number) option. Useful to update the UI to display temporary success state.
## Acknowledgements
This hook is powered by [clipboard-copy](https://github.com/feross/clipboard-copy), the lightweight copy to clipboard for the web.
## License
MIT