I'm trying to handle copy to clipboard in React
with useRef
hook. How can I achieve it without any additional libraries? Here is my code but it throws an error myRef.current.select is not a function
.
import React, { useRef } from "react";
const Element = () => {
const myRef = useRef();
const copyToClipboard = () => {
myRef.current.select();
document.execCommand("copy");
};
return (
<div>
<span onClick={copyToClipboard} ref={myRef}>
Text to be copied
</span>
</div>
);
};
export default Element;
Select the text or graphics you want to copy, and press Ctrl+C. Each selection appears in the Clipboard, with the latest at the top. Optionally, repeat step 2 until you've copied all the items you want to use. Tip: After you open the Clipboard, it stores content that you copy or cut from anywhere.
The useRef Hook allows you to persist values between renders. It can be used to store a mutable value that does not cause a re-render when updated. It can be used to access a DOM element directly.
Run the following snippet(s).
CopyToClipElement
component (with React Hooks) which handles the copy for given text prop. Use this component in your render.const CopyToClipElement = ({ text }) => {
const myRef = React.useRef(null);
const [data, setData] = React.useState(text);
React.useEffect(() => setData(text), [text]);
React.useEffect(() => {
if (myRef.current && data) {
myRef.current.select();
document.execCommand("copy");
setData(null);
}
}, [data, myRef.current]);
return <div>{data && <textarea ref={myRef}>{data}</textarea>}</div>;
};
const Element = () => {
const [copyText, setCopyText] = React.useState("");
const data = ["Text to be copied", "Copy foo"];
return (
<div>
{data.map((text) => (
<span
style={{ margin: "10px", cursor: "pointer", color: 'blue' }}
onClick={() => setCopyText(text)}
>
{text}
</span>
))}
<CopyToClipElement text={copyText} />
</div>
);
};
const domContainer = document.querySelector('#app');
ReactDOM.render(<Element/>, domContainer);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="app"> </div>
copyToClipboard
in plain JS.const copyToClipboard = (text: string) => {
const ta = document.createElement("textarea");
ta.innerText = text;
document.body.appendChild(ta);
ta.select();
document.execCommand("copy");
ta.remove();
};
const Element = () => {
const data = ["Text to be copied", "Copy Bar"];
return (
<div>
{data.map((text) => (
<span
style={{ margin: "10px", cursor: "pointer", color: 'red' }}
onClick={() => copyToClipboard(text)}
>
{text}
</span>
))}
</div>
);
};
const domContainer = document.querySelector('#app');
ReactDOM.render(<Element />, domContainer);
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="app"> </div>
Take a look at this solution, I just adapted it to your use case.
const copyToClipboard = () => {
const range = document.createRange();
range.selectNode(myRef.current);
window.getSelection().addRange(range);
try {
// Now that we've selected the anchor text, execute the copy command
const successful = document.execCommand('copy');
const msg = successful ? 'successful' : 'unsuccessful';
console.log('Copy email command was ' + msg);
} catch(err) {
console.log('Oops, unable to copy');
}
// Remove the selections - NOTE: Should use
// removeRange(range) when it is supported
window.getSelection().removeAllRanges();
};
Ciao, I found a solution but I had to use input
instead of span
. And I haven't used useRef
hook but just a variable (let myInput = null;
) and then on input ref I wrote ref={(ref) => myInput = ref}
. In this way, your copyToClipboard
works.
The code:
function App() {
let myInput = null;
const copyToClipboard = () => {
myInput.select();
document.execCommand("copy");
alert("Copied the text: " + myInput.value);
};
return (
<div>
<input readOnly value="Text to copy" onClick={copyToClipboard} ref={(ref) => myInput = ref} />
</div>
);
}
Here the codesandbox example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With