DEV Community

Using React Portals in TalkJS HTMLPanels

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

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.

function MyComponent(props) {
  return ReactDOM.createPortal(

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 and ConversationBuilder object are passed as props. Read our Getting started guide to find out how to set these up.

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

  componentDidMount() {
    this.chatbox = this.props.session.createChatbox(this.props.conversation);

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

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.

constructor {

  this.state = {
    panelReady: false

  this.chatboxContainer = React.createRef();

Then, create the HTML inside componentDidMount:

componentDidMount() {
  const chatbox = this.props.session.createChatbox(this.props.conversation);

  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(() => {
        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(
      <EmailForm />

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 or send an email to

Happy coding!

Top comments (0)