admin管理员组文章数量:1125765
I'm using ReactJS and when a user clicks a link I want to copy some text to the clipboard.
I am using Chrome 52 and I do not need to support any other browsers.
I can't see why this code does not result in the data being copied to the clipboard. (the origin of the code snippet is from a Reddit post).
Am I doing this wrong? Can anyone suggest is there a "correct" way to implement copy to clipboard using reactjs?
copyToClipboard = (text) => {
console.log('text', text)
var textField = document.createElement('textarea')
textField.innerText = text
document.body.appendChild(textField)
textField.select()
document.execCommand('copy')
textField.remove()
}
I'm using ReactJS and when a user clicks a link I want to copy some text to the clipboard.
I am using Chrome 52 and I do not need to support any other browsers.
I can't see why this code does not result in the data being copied to the clipboard. (the origin of the code snippet is from a Reddit post).
Am I doing this wrong? Can anyone suggest is there a "correct" way to implement copy to clipboard using reactjs?
copyToClipboard = (text) => {
console.log('text', text)
var textField = document.createElement('textarea')
textField.innerText = text
document.body.appendChild(textField)
textField.select()
document.execCommand('copy')
textField.remove()
}
Share
Improve this question
edited Sep 15, 2016 at 0:49
EugZol
6,54524 silver badges44 bronze badges
asked Sep 14, 2016 at 23:52
Duke DougalDuke Dougal
26.3k33 gold badges96 silver badges133 bronze badges
5
- 2 Did you try using 3rd party solutions, like clipboardjs.com or github.com/zeroclipboard/zeroclipboard? – EugZol Commented Sep 15, 2016 at 0:51
- 58 @EugZol I really prefer to write code rather than add another dependency, assuming the code is fairly small. – Duke Dougal Commented Sep 15, 2016 at 1:04
- Check these answers stackoverflow.com/questions/400212/… – elmeister Commented Sep 15, 2016 at 1:35
- @elmeister the question is specific to reactjs – Duke Dougal Commented Sep 15, 2016 at 2:39
- must we use a library just to copy? really?? – codemon Commented Jul 27, 2022 at 16:35
31 Answers
Reset to default 1 2 Next 839Use this simple inline onClick function on a button if you want to programatically write data to the clipboard.
onClick={() => {navigator.clipboard.writeText(this.state.textToCopy)}}
I personally don't see the need for a library for this. Looking at http://caniuse.com/#feat=clipboard it's pretty widely supported now, however you can still do things like checking to see if the functionality exists in the current client and simply hide the copy button if it doesn't.
import React from 'react';
class CopyExample extends React.Component {
constructor(props) {
super(props);
this.state = { copySuccess: '' }
}
copyToClipboard = (e) => {
this.textArea.select();
document.execCommand('copy');
// This is just personal preference.
// I prefer to not show the whole text area selected.
e.target.focus();
this.setState({ copySuccess: 'Copied!' });
};
render() {
return (
<div>
{
/* Logical shortcut for only displaying the
button if the copy command exists */
document.queryCommandSupported('copy') &&
<div>
<button onClick={this.copyToClipboard}>Copy</button>
{this.state.copySuccess}
</div>
}
<form>
<textarea
ref={(textarea) => this.textArea = textarea}
value='Some text to copy'
/>
</form>
</div>
);
}
}
export default CopyExample;
Update: Rewritten using React Hooks in React 16.7.0-alpha.0
import React, { useRef, useState } from 'react';
export default function CopyExample() {
const [copySuccess, setCopySuccess] = useState('');
const textAreaRef = useRef(null);
function copyToClipboard(e) {
textAreaRef.current.select();
document.execCommand('copy');
// This is just personal preference.
// I prefer to not show the whole text area selected.
e.target.focus();
setCopySuccess('Copied!');
};
return (
<div>
{
/* Logical shortcut for only displaying the
button if the copy command exists */
document.queryCommandSupported('copy') &&
<div>
<button onClick={copyToClipboard}>Copy</button>
{copySuccess}
</div>
}
<form>
<textarea
ref={textAreaRef}
value='Some text to copy'
/>
</form>
</div>
);
}
You can get this done without the need of an external library, e.g: within a button
<button
onClick={() => navigator.clipboard.writeText('Copy this text to clipboard')}
>
Copy
</button>
for internet explorer 11 and older browsers you might need to change the code a bit here is an example:
<button
onClick={() => window.clipboardData.setData("Text", 'Copy this text to clipboard')}>
Copy
</button>
You should definitely consider using a package like @Shubham above is advising, but I created a working codepen based on what you described: http://codepen.io/dtschust/pen/WGwdVN?editors=1111 . It works in my browser in chrome, perhaps you can see if there's something I did there that you missed, or if there's some extended complexity in your application that prevents this from working.
// html
<html>
<body>
<div id="container">
</div>
</body>
</html>
// js
const Hello = React.createClass({
copyToClipboard: () => {
var textField = document.createElement('textarea')
textField.innerText = 'foo bar baz'
document.body.appendChild(textField)
textField.select()
document.execCommand('copy')
textField.remove()
},
render: function () {
return (
<h1 onClick={this.copyToClipboard}>Click to copy some text</h1>
)
}
})
ReactDOM.render(
<Hello/>,
document.getElementById('container'))
The simplest way will be use the react-copy-to-clipboard
npm package.
You can install it with the following command
npm install --save react react-copy-to-clipboard
Use it in the following manner.
const App = React.createClass({
getInitialState() {
return {value: '', copied: false};
},
onChange({target: {value}}) {
this.setState({value, copied: false});
},
onCopy() {
this.setState({copied: true});
},
render() {
return (
<div>
<input value={this.state.value} size={10} onChange={this.onChange} />
<CopyToClipboard text={this.state.value} onCopy={this.onCopy}>
<button>Copy</button>
</CopyToClipboard>
<div>
{this.state.copied ? <span >Copied.</span> : null}
</div>
<br />
<input type="text" />
</div>
);
}
});
ReactDOM.render(<App />, document.getElementById('container'));
A detailed explanation is provided at the following link
https://www.npmjs.com/package/react-copy-to-clipboard
Here is a running fiddle.
Best solution with react hooks, no need of external libraries for that
import React, { useState } from 'react';
const MyComponent = () => {
const [copySuccess, setCopySuccess] = useState('');
// your function to copy here
const copyToClipBoard = async copyMe => {
try {
await navigator.clipboard.writeText(copyMe);
setCopySuccess('Copied!');
} catch (err) {
setCopySuccess('Failed to copy!');
}
};
return (
<div>
<Button onClick={() => copyToClipBoard('some text to copy')}>
Click here to copy
</Button>
// after copying see the message here
{copySuccess}
</div>
)
}
check here for further documentation about navigator.clip board , navigator.clipboard documentation navigotor.clipboard is supported by a huge number of browser look here supported browser
Clipboard is well supported by major browsers in 2021. One approach would be to first build a copy to clipboard function and then call it using the onClick
event handler.
function copy(text){
navigator.clipboard.writeText(text)
}
To prevent hard coding, let's suppose the string
is assigned to a variable named someText
<span onClick={() => copy(someText)}>
{someText}
</span>
You can use event clipboardData collection method e.clipboardData.setData(type, content)
.
In my opinion is the most straightforward method to achieve pushing something inside the clipboard, check this out (I've used that to modify data while native copying action):
...
handleCopy = (e) => {
e.preventDefault();
e.clipboardData.setData('text/plain', 'Hello, world!');
}
render = () =>
<Component
onCopy={this.handleCopy}
/>
I followed that path: https://developer.mozilla.org/en-US/docs/Web/Events/copy
Cheers!
EDIT: For testing purposes, I've added codepen: https://codepen.io/dprzygodzki/pen/ZaJMKb
I've taken a very similar approach as some of the above, but made it a little more concrete, I think. Here, a parent component will pass the url (or whatever text you want) as a prop.
import * as React from 'react'
export const CopyButton = ({ url }: any) => {
const copyToClipboard = () => {
const textField = document.createElement('textarea');
textField.innerText = url;
document.body.appendChild(textField);
textField.select();
document.execCommand('copy');
textField.remove();
};
return (
<button onClick={copyToClipboard}>
Copy
</button>
);
};
Here's another use case, if you would like to copy the current url to your clipboard:
Define a method
const copyToClipboard = e => {
navigator.clipboard.writeText(window.location.toString())
}
Call that method
<button copyToClipboard={shareLink}>
Click to copy current url to clipboard
</button>
No need to install third party packages. I try to keep it as simple as possible. This worked well for me.
import React, { useState } from "react"
function MyApp() {
const [copySuccess, setCopySuccess] = useState(null);
const copyToClipBoard = async copyMe => {
try {
await navigator.clipboard.writeText(copyMe);
setCopySuccess('Copied!');
}
catch (err) {
setCopySuccess('Failed to copy!');
}
};
return (
<button onClick={(e) => copyToClipBoard(what you want to copy goes here)} >
My button
</button>
)
}
Your code should work perfectly, I use it the same way. Only make sure that if the click event is triggered from within a pop up screen like a bootstrap modal or something, the created element has to be within that modal otherwise it won't copy. You could always give the id of an element within that modal (as a second parameter) and retrieve it with getElementById, then append the newly created element to that one instead of the document. Something like this:
copyToClipboard = (text, elementId) => {
const textField = document.createElement('textarea');
textField.innerText = text;
const parentElement = document.getElementById(elementId);
parentElement.appendChild(textField);
textField.select();
document.execCommand('copy');
parentElement.removeChild(textField);
}
Fully working React component using Material UI
For a better understanding, I've prepared a CodeSandbox as well. Hope that helps.
import { useState } from "react";
import { IconButton, Snackbar } from "@mui/material";
import ShareIcon from "@mui/icons-material/Share";
const CopyToClipboardButton = () => {
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen(true);
navigator.clipboard.writeText(window.location.toString());
};
return (
<>
<IconButton onClick={handleClick} color="primary">
<ShareIcon />
</IconButton>
<Snackbar
message="Copied to clibboard"
anchorOrigin={{ vertical: "top", horizontal: "center" }}
autoHideDuration={20000}
onClose={() => setOpen(false)}
open={open}
/>
</>
);
};
export default CopyToClipboardButton;
Here's what the button looks like:
And when you click it:
Source: https://fwuensche.medium.com/react-button-to-copy-to-clipboard-75ef5ecdc708
This work for me:
const handleCopyLink = useCallback(() => {
const textField = document.createElement('textarea')
textField.innerText = url
document.body.appendChild(textField)
if (window.navigator.platform === 'iPhone') {
textField.setSelectionRange(0, 99999)
} else {
textField.select()
}
document.execCommand('copy')
textField.remove()
}, [url])
first create BTN then add this onClick:
onClick={() => navigator.clipboard.writeText(textState)}
or
onClick={() => navigator.clipboard.writeText('Your text for copy')}
The plain simple answer will be
navigator.clipboard.writeText("value")
navigator.clipboard doesn't work over http connection according to their document. So you can check if it's coming undefined and use document.execCommand('copy') instead, this solution should cover almost all the browsers
const defaultCopySuccessMessage = 'ID copied!'
const CopyItem = (props) => {
const { copySuccessMessage = defaultCopySuccessMessage, value } = props
const [showCopySuccess, setCopySuccess] = useState(false)
function fallbackToCopy(text) {
if (window.clipboardData && window.clipboardData.setData) {
// IE specific code path to prevent textarea being shown while dialog is visible.
return window.clipboardData.setData('Text', text)
} else if (document.queryCommandSupported && document.queryCommandSupported('copy')) {
const textarea = document.createElement('textarea')
textarea.innerText = text
// const parentElement=document.querySelector(".up-CopyItem-copy-button")
const parentElement = document.getElementById('copy')
if (!parentElement) {
return
}
parentElement.appendChild(textarea)
textarea.style.position = 'fixed' // Prevent scrolling to bottom of page in MS Edge.
textarea.select()
try {
setCopySuccess(true)
document.execCommand('copy') // Security exception may be thrown by some browsers.
} catch (ex) {
console.log('Copy to clipboard failed.', ex)
return false
} finally {
parentElement.removeChild(textarea)
}
}
}
const copyID = () => {
if (!navigator.clipboard) {
fallbackToCopy(value)
return
}
navigator.clipboard.writeText(value)
setCopySuccess(true)
}
return showCopySuccess ? (
<p>{copySuccessMessage}</p>
) : (
<span id="copy">
<button onClick={copyID}>Copy Item </button>
</span>
)
}
And you can just call and reuse the component anywhere you'd like to
const Sample=()=>(
<CopyItem value="item-to-copy"/>
)
use this command to pass your value to the function
var promise = navigator.clipboard.writeText(newClipText)
For those people who are trying to select from the DIV instead of the text field, here is the code. The code is self-explanatory but comment here if you want more information:
import React from 'react';
....
//set ref to your div
setRef = (ref) => {
// debugger; //eslint-disable-line
this.dialogRef = ref;
};
createMarkeup = content => ({
__html: content,
});
//following function select and copy data to the clipboard from the selected Div.
//Please note that it is only tested in chrome but compatibility for other browsers can be easily done
copyDataToClipboard = () => {
try {
const range = document.createRange();
const selection = window.getSelection();
range.selectNodeContents(this.dialogRef);
selection.removeAllRanges();
selection.addRange(range);
document.execCommand('copy');
this.showNotification('Macro copied successfully.', 'info');
this.props.closeMacroWindow();
} catch (err) {
// console.log(err); //eslint-disable-line
//alert('Macro copy failed.');
}
};
render() {
return (
<div
id="macroDiv"
ref={(el) => {
this.dialogRef = el;
}}
// className={classes.paper}
dangerouslySetInnerHTML={this.createMarkeup(this.props.content)}
/>
);
}
import React, { Component } from 'react';
export default class CopyTextOnClick extends Component {
copyText = () => {
this.refs.input.select();
document.execCommand('copy');
return false;
}
render () {
const { text } = this.state;
return (
<button onClick={ this.copyText }>
{ text }
<input
ref="input"
type="text"
defaultValue={ text }
style={{ position: 'fixed', top: '-1000px' }} />
</button>
)
}
}
make a componant as follows :-
//react functional componant
import React, { useState } from "react";
function CopyToClipboard(props) {
const [copied, setCopied] = useState("copy");
return (
<div
className="font-medium mr-4 text-green-700 cursor-pointer"
onClick={() => {
navigator.clipboard.writeText(props.text);
setCopied("copied");
}}>
{copied}
</div>
);
}
export default CopyToClipboard;
//then use this componant anywhere
<CopyToClipboard text={"text you want to copy"}></CopyToClipboard>
//it will give a text saying "copy"`enter code here` and after clicking on that text, text provided with props will get copied
If you want to select from the DIV instead of the text field, here is the code. The "code" is the value that has to be copied
import React from 'react'
class CopyToClipboard extends React.Component {
copyToClipboard(code) {
var textField = document.createElement('textarea')
textField.innerText = code
document.body.appendChild(textField)
textField.select()
document.execCommand('copy')
textField.remove()
}
render() {
return (
<div onClick={this.copyToClipboard.bind(this, code)}>
{code}
</div>
)
}
}
export default CopyToClipboard
Found best way to do it. i mean the fastest way: w3school
https://www.w3schools.com/howto/howto_js_copy_clipboard.asp
Inside a react functional component. Create a function named handleCopy:
function handleCopy() {
// get the input Element ID. Save the reference into copyText
var copyText = document.getElementById("mail")
// select() will select all data from this input field filled
copyText.select()
copyText.setSelectionRange(0, 99999)
// execCommand() works just fine except IE 8. as w3schools mention
document.execCommand("copy")
// alert the copied value from text input
alert(`Email copied: ${copyText.value} `)
}
<>
<input
readOnly
type="text"
value="[email protected]"
id="mail"
/>
<button onClick={handleCopy}>Copy email</button>
</>
If not using React, w3schools also have one cool way to do this with tooltip included: https://www.w3schools.com/howto/tryit.asp?filename=tryhow_js_copy_clipboard2
If using React, a cool think to do: Use a Toastify to alert the message. https://github.com/fkhadra/react-toastify This is the lib very easy to use. After installation, you may be able to change this line:
alert(`Email copied: ${copyText.value} `)
For something like:
toast.success(`Email Copied: ${copyText.value} `)
If you want to use it, dont forget to Install toastify. import ToastContainer and also toasts css:
import { ToastContainer, toast } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"
and add the toast container inside return.
import React from "react"
import { ToastContainer, toast } from "react-toastify"
import "react-toastify/dist/ReactToastify.css"
export default function Exemple() {
function handleCopy() {
var copyText = document.getElementById("mail")
copyText.select()
copyText.setSelectionRange(0, 99999)
document.execCommand("copy")
toast.success(`Hi! Now you can: ctrl+v: ${copyText.value} `)
}
return (
<>
<ToastContainer />
<Container>
<span>E-mail</span>
<input
readOnly
type="text"
value="[email protected]"
id="mail"
/>
<button onClick={handleCopy}>Copy Email</button>
</Container>
</>
)
}
copyclip = (item) => {
var textField = document.createElement('textarea')
textField.innerText = item
document.body.appendChild(textField)
textField.select()
document.execCommand('copy')
this.setState({'copy':"Copied"});
textField.remove()
setTimeout(() => {
this.setState({'copy':""});
}, 1000);
}
<span className="cursor-pointer ml-1" onClick={()=> this.copyclip(passTextFromHere)} >Copy</span> <small>{this.state.copy}</small>
You can also use react hooks into function components or stateless components with this piece of code: PS: Make sure you install useClippy through npm/yarn with this command: npm install use-clippy or yarn add use-clippy
import React from 'react';
import useClippy from 'use-clippy';
export default function YourComponent() {
// clipboard is the contents of the user's clipboard.
// setClipboard('new value') wil set the contents of the user's clipboard.
const [clipboard, setClipboard] = useClippy();
return (
<div>
{/* Button that demonstrates reading the clipboard. */}
<button
onClick={() => {
alert(`Your clipboard contains: ${clipboard}`);
}}
>
Read my clipboard
</button>
{/* Button that demonstrates writing to the clipboard. */}
<button
onClick={() => {
setClipboard(`Random number: ${Math.random()}`);
}}
>
Copy something
</button>
</div>
);
}
const handleCopy = async () => {
let copyText = document.getElementById('input') as HTMLInputElement;
copyText.select();
document.execCommand('copy');
};
return (
<TextField
variant="outlined"
value={copyText}
id="input"
/>
);
This is work for me.
here is my code:
import React from 'react'
class CopyToClipboard extends React.Component {
textArea: any
copyClipBoard = () => {
this.textArea.select()
document.execCommand('copy')
}
render() {
return (
<>
<input style={{display: 'none'}} value="TEXT TO COPY!!" type="text" ref={(textarea) => this.textArea = textarea} />
<div onClick={this.copyClipBoard}>
CLICK
</div>
</>
)
}
}
export default CopyToClipboard
<input
value={get(data, "api_key")}
styleName="input-wrap"
title={get(data, "api_key")}
ref={apikeyObjRef}
/>
<div
onClick={() => {
apikeyObjRef.current.select();
if (document.execCommand("copy")) {
document.execCommand("copy");
}
}}
styleName="copy"
>
复制
</div>
you can use useRef to select text inside an element then copy it to clipboard
import React, { useRef } from "react";
const Comp = () => {
const copyTxt = useRef();
const handleCopyTxt = () => {
let txtDiv = copyTxt.current;
if (document.selection) {
// IE
var range = document.body.createTextRange();
range.moveToElementText(txtDiv);
range.select();
} else if (window.getSelection) {
// other browsers
var range = document.createRange();
range.selectNode(txtDiv);
window.getSelection().removeAllRanges();
window.getSelection().addRange(range);
}
document.execCommand("copy");
}
return ( <div ref={copyTxt} > some text to copied </div> )
}
Inspired by @nate 's answer I have created a withCopyText
react hook. And, added navigator.clipboard.writeText
support with execCommand
fallback.
The hook means that it can be reused across many components without repeating code. See the example component CopyText
for implementation.
import React, { useRef, useState } from 'react';
const withCopyText = (textElementRef) => {
if (!textElementRef) throw 'withCopyText: ref is required';
const [copyStatus, setCopyStatus] = useState('');
const [support, setSupport] = useState({
navigatorClipboard: !!navigator.clipboard,
exec: !!document.queryCommandSupported('copy'),
});
const copyToClipboard = (e) => {
if ('' !== copyStatus) {
setCopyStatus('');
await new Promise((resolve) => setTimeout(resolve, 200));
}
// clipboard.writeText has wide but not 100% support
// https://caniuse.com/?search=writeText
if (support.navigatorClipboard) {
try {
navigator.clipboard.writeText(textElementRef.current.value);
return setCopyStatus('success');
} catch (e) {
setSupport({ ...support, navigatorClipboard: false });
}
}
// execCommand has > 97% support but is deprecated, use it as a fallback
// https://caniuse.com/?search=execCommand
// https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
if (!support.navigatorClipboard) {
try {
textElementRef.current.select();
document.execCommand('copy');
e.target.focus();
setCopyStatus('success');
} catch (e) {
setSupport({ ...support, exec: false });
return setCopyStatus('fail');
}
}
};
return {
copyStatus,
copyToClipboard,
support: Object.values(support).includes(true),
};
};
const CopyText = ({ text }) => {
const textElementRef = useRef(null);
const { copyStatus, copyToClipboard, support } = withCopyText(textElementRef);
return (
<span>
{support && <button onClick={copyToClipboard}>Copy</button>}
{'success' === copyStatus && <span>Copied to clipboard!</span>}
{'fail' === copyStatus && <span>Sorry, copy to clipboard failed</span>}
<input type="text" ref={textElementRef} value={text} readOnly={true} />
</span>
);
};
export { CopyText, withCopyText };
本文标签: javascriptIn reactJShow to copy text to clipboardStack Overflow
版权声明:本文标题:javascript - In reactJS, how to copy text to clipboard? - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736673715a1947062.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论