0

Below is a simplified version of my app where there is a template rendered on the page and it is filled with the help of two text inputs.

It's a "template generator" type app and I want to be able to copy the completed template as rendered on the page so that it can be pasted elsewhere. To do this normally you would click + drag to highlight the rendered html then right click + copy or ctrl + c.

How can I convert my HTML to a rendered version so that I can copy to clipboard with the help of my react-clipboard button? Or is there another way I can achieve this?

If anything isn't clear please let me know - thanks in advance

TL;DR: Currently when you click on "copy to clipboard" the app is copying html. I want it to copy the contents as it would be rendered on a webpage. For example hello world converted and copied should copy a red h1 that says hello world.

import React, { Component } from 'react';
import { TextField } from 'material-ui';
import Clipboard from 'react-clipboard.js';
import './App.css';
const logo = 'https://www.google.co.uk/images/branding/googlelogo/2x/googlelogo_color_120x44dp.png';

class App extends Component {
  constructor() {
    super();
    this.state = {
      name: 'Default Name',
      title: 'Default Title'
    };
  }
  componentDidMount() {
    this.setState({template: this.createTemplate(this.state.name, this.state.title) });
  }
  createTemplate(name, title) {
    const template = `<!DOCTYPE html>
    <html>
      <head>
        <link href="https://fonts.googleapis.com/css?family=Montserrat:400,700" rel="stylesheet">
      </head>
      <body>
        <h1>${name}</h1>
        <h2>${title}</h2>
      </body>
    </html>`

    this.setState({template});
  }
  updateValue(event, type) {
    if(type === 'name') {
      this.setState({name: event.target.value});
      this.createTemplate(event.target.value, this.state.title);
    } else {
      this.setState({title: event.target.value});
      this.createTemplate(this.state.name, event.target.value);
    }
  }
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
        <h1 className="App-title">Signature Builder</h1>
        </header>
        <div>
          <br/>
          <TextField hintText="Name" onChange={(e) => this.updateValue(e, 'name')} />
          <TextField hintText="Title" onChange={(e) => this.updateValue(e, 'title')} />
          <div style={{textAlign: 'left', margin: 10}} dangerouslySetInnerHTML={{ __html: this.state.template }} />
          <Clipboard data-clipboard-text={this.state.template}>
            copy to clipboard
          </Clipboard>
        </div>
      </div>
    );
  }
}

export default App;
WillKre
  • 6,280
  • 6
  • 32
  • 62

2 Answers2

2

The problem is that react-clipboard doesn't support copying HTML text; you'll just have to do it using normal JS. Unfortunately, clipboard APIs are fairly finicky.

You can get around some of the issues by just not using a button and capturing the onCopy event to change the content copied by the clipboard.

const copyAction = e => {
  e.preventDefault()
  e.clipboardData.setData('text/plain', 'This is plaintext; try pasting into a program that supports rich text')
  e.clipboardData.setData('text/html', '<h1>Hello</h1><h2>World</h2>')
  console.log('Copy event captured!')
}

const App = () => (
  <div onCopy={copyAction}>
    Copy me!
  </div>)
  
ReactDOM.render(<App />,
  document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='root' />

Of course, the content of the HTML text itself can be created as you please whether it's through your template literals or through using ReactDOMServer like coreyward suggested.


More info:

Kevin Raoofi
  • 1,023
  • 11
  • 16
1

You can use ReactDOMServer.renderToStaticMarkup to convert your React component into a string without any of the React-specific tags. If you expect the HTML to be hydrated later you can use renderToString instead.

https://reactjs.org/docs/react-dom-server.html

coreyward
  • 77,547
  • 20
  • 137
  • 166
  • It's not a react component though it's a string (see `const template`) - that's essentially what I want copied but 'rendered' as on a webpage (or whatever the word is). Would it work the same with that? – WillKre Apr 11 '18 at 15:11
  • Oh sorry, I misunderstood entirely. You want to copy rich text from an HTML snippet? You'll could try to render HTML to the page, highlight it, and trigger a copy, but no guarantees. – coreyward Apr 11 '18 at 15:20