Using React Portals in TalkJS HTMLPanels
Tags: javascript, webdev
Published: 2020-09-25 11:45:05

# What are HTML Panels?

TalkJS provides an easy way to add chat functionality to your website, with a nice pre-built user interface that you can customise. But sometimes, you want to add a bit of your own UI to the chat. TalkJS is rendered inside an iframe, so you can't edit the DOM directly, but we have a feature called HTML Panels that lets you load your own web page in a panel above the message field. It lets you do things like this:

![TalkJS chat with an email form](https://talkjs.com/docs/img/html-panel.png)

The email form you see there is rendered in an HTML panel.

# What are React portals?

Portals are a way for a React component to render its children in a different DOM node.

```JavaScript
function MyComponent(props) {
  return ReactDOM.createPortal(
    <p>Hello</p>,
    document.getElementById("someOtherElement")
  );
}
```

You can pass anything that's renderable by React to `createPortal`, including `props.children`.

# Combining Portals with HTML Panels

So let's say you're writing a `Chatbox` component, and you want it to render a TalkJS chatbox, and you want it to contain an email form like above, but you'd also like that form to be part of your main React application.

To start, let's have a look at what the Chatbox component might look like. I'm assuming that a [`Session`](https://talkjs.com/docs/Reference/JavaScript_Chat_SDK/Session.html) and [`ConversationBuilder`](https://talkjs.com/docs/Reference/JavaScript_Chat_SDK/ConversationBuilder.html) object are passed as props. Read our [Getting started](https://talkjs.com/docs/Getting_Started/Frameworks/React.html) guide to find out how to set these up.

```JavaScript
class Chatbox extends React.Component {
  constructor(props) {
    super(props);
    this.chatboxContainer = React.createRef();
  }

  componentDidMount() {
    this.chatbox = this.props.session.createChatbox(this.props.conversation);
    this.chatbox.mount(this.chatboxContainer.current);
  }

  render() {
    return <div ref={this.chatboxContainer}>
    </div>
  }
}
```

Now let's add a HTML panel to hold our email form. First create an HTML file that just contains a div to hold our HTML Panel contents.

    <div id="panelContent"></div>

Save it somere so that it is served from the same origin as your React application.

Next, we'll update our Chatbox component. First, we'll add a `panelReady` flag in our state.

```JavaScript
constructor {
  super()

  this.state = {
    panelReady: false
  };

  this.chatboxContainer = React.createRef();
}
```

Then, create the HTML inside `componentDidMount`:

```JavaScript
componentDidMount() {
  const chatbox = this.props.session.createChatbox(this.props.conversation);
  chatbox.mount(this.chatboxContainer.current);

  const panelPromise = chatbox.createHtmlPanel({
    url: "path/to/file.html", // Should point to the file created above.
    height: 300,
    show: true
});
 
  panelPromise.then((panel) => {
    panel.DOMContentLoadedPromise.then(() => {
      this.setState({
        panelReady: true,
        panelNode: panel.window.document.getElementById("panelContent")
      })
    });
  });
}
```

And then it's time to render the portal when the panel is ready. Update the `Chatbox`'s render method like this

```
render() {
  return <div ref={this.chatboxContainer}>
    {this.state.panelReady && ReactDOM.createPortal(
      this.state.panelNode,
      <EmailForm />
    )}
  </div>
}
```

`EmailForm` can be any component you like, and it works just like any other React component, even events bubble from the EmailForm to your Chatbox component.

If you run into any issues, feel free to get in touch via the popup on [our website](https://talkjs.com) or send an email to dev@talkjs.com

Happy coding!