Copy to clipboard is copying value with two newlines

Viewed 356

I have a code that copy the text value of a paragraph element in React to the clipboard.

The code is working (copying the value to the clipboard) but is it copying the value plus two newlines into the clipboard.

For example if I want to copy the value '2345678' it will copy:

'2345678



'
import './CopyClipboard.css';

class CopyClipboard extends React.Component {
    constructor(props) {
        super(props);
        this.textContent = null;
        this.state = {
            copied: false
        };
    }

    copyToClipboard = async e => {
        window.getSelection().removeAllRanges();
        var range = document.createRange();
        range.selectNode(this.textContent);
        window.getSelection().addRange(range);
        document.execCommand("copy");
        window.getSelection().removeAllRanges();
        this.setState({ copied: true });
    };

    initRef = c => (this.textContent = c);

    render() {
        const { copied } = this.state;
        return (
            <div className="positioning">
                <p onMouseLeave={() => this.setState({ copied: false })} onClick={this.copyToClipboard} ref={this.initRef}>
                    {this.props.value}
                </p>
                {copied === false ? <p className="success">Copy to Clipboard</p> : <p className="success">Copied!!!</p>}
            </div>
        );
    }
}

export default CopyClipboard;

maybe someone can understand what am I doing wrong here ?

Thanks!

so I managed to get it working using @ChrisSandvik solution to use clipboard-polyfill

the code:

import React from 'react';
import * as clipboard from "clipboard-polyfill";
import './CopyClipboard.css';

class CopyClipboard extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            copied: false
        };
    }

    copyText = e => {
        clipboard.writeText(this.props.value);
        this.setState({ copied: true });
    };

    render() {
        const { copied } = this.state;
        return (
            <div className="positioning">
                <p onMouseLeave={() => this.setState({ copied: false })} onClick={this.copyText} ref={this.initRef}>
                    {this.props.value}
                </p>
                {copied === false ? <p className="success">Copy to Clipboard</p> : <p className="success">Copied!!!</p>}
            </div>
        );
    }
}

export default CopyClipboard;

EDIT 2:

I found the problem, the value passed was ok, but <p></p> elements have default css that is effecting the value that you will get when you retrieve it. you can fix it by either using <span> or overriding the <p> default css

2 Answers

I believe Venecovsky might be on the right track with the line breaks. However, another solution that I tend to lean towards when dealing with clipboard stuff in React is to use the clipboard-polyfil package.

This would reduce your code down to:

copyToClipboard = async e => {
    clipboard.writeText(this.props.value);
};

And is also guaranteed to work better cross browser and cross device.

You also wouldn't have to deal with refs!

EDIT:

I made a working and very simple demo you can check out here: https://codesandbox.io/s/strange-darkness-wzrjz

const ClipboardThing = props => {
  const copyText = e => {
    clipboard.writeText(props.value);
    changeButtonText(e.target, "Copied!");
  };

  const changeButtonText = (button, text) => {
    const original = button.textContent;
    button.textContent = text;
    setTimeout(() => {
      button.textContent = original;
    }, 1200);
  };

  return (
    <div>
      <p>{props.value}</p>
      <button onClick={copyText}>Copy Text</button>
    </div>
  );
};

function App() {
  return (
    <div className="App">
      <ClipboardThing value="test text" />
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard-polyfill/2.8.1/clipboard-polyfill.js"></script>

<div id="root"></div>

Edit:

Use span instead of p.

<span onMouseLeave={() => this.setState({ copied: false })} onClick={this.copyToClipboard} ref={this.initRef}>{this.props.value}</span >

Old:

Try adding it in one line only, without indenting the code (remove enter and spaces of the code).

<p onMouseLeave={() => this.setState({ copied: false })} onClick={this.copyToClipboard} ref={this.initRef}>{this.props.value}</p>

One thing you can check is this.props.value.length, maybe the value is already comming with two extra line.

OR

One thing you can do is use .trim to remove the extra line breaks.

Related