Author avatar

Gaurav Singhal

How to Render a React Component Inside a Bootstrap Popover

Gaurav Singhal

  • Mar 14, 2020
  • 8 Min read
  • 5,570 Views
  • Mar 14, 2020
  • 8 Min read
  • 5,570 Views
Web Development
Front End Web Development
Client-side Framework
React

Introduction

Sometimes you find yourself wanting more than the libraries you are using have to offer. For example, let's say you want to render a React component inside a bootstrap popover. Sounds easy, right? Well, it turns out not to be that simple. This guide will further explore this scenario and offer two approaches for rendering a component inside a bootstrap popover.

Conventional Static Projects

Assume you have a standard static project with no moduler or transpiler, just very basic HTML files that are bootstrap linked across multiple pages.

You'll have the Bootstrap CSS link in the head, and the jQuery, Popper.js and Bootstrap script just before the body ends. The basic HTML template would look as follows.

1<!DOCTYPE html>
2<html lang="en">
3  <head>
4    <meta charset="UTF-8" />
5    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
7    <title>Static Template</title>
8    <link
9      rel="stylesheet"
10      href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css"
11      integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO"
12      crossorigin="anonymous"
13    />
14  </head>
15  <body>
16    <!-- -->
17
18    <script
19      src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
20      integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
21      crossorigin="anonymous"
22    ></script>
23    <script
24      src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"
25      integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49"
26      crossorigin="anonymous"
27    ></script>
28    <script
29      src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"
30      integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy"
31      crossorigin="anonymous"
32    ></script>
33  </body>
34</html>
html

Add the Popover Button

Create a button that will trigger the popover. Give it an id of value popover.

1<button type="button" class="btn btn-lg btn-primary" id="popover">
2  Click to toggle popover
3</button>
html

Before the body ends, write a <script> block and initialize the popover by selecting the id of the button.

1<script>
2  $(document).ready(function() {
3    $("button#popover").popover();
4  });
5</script>
html

As desired, pass a few options into the popover() to display HTML content in it.

1// ..
2
3$("button#popover").popover({
4  html: true,
5  content: `<div>Hello</div>`
6});
7// ..
js

You can see the popover in action when you click on the button.

Now, instead of directly putting in the content, you will add a React component.

Insert React Component

First, add the React CDN links to the HTML file.

1<script
2  crossorigin
3  src="https://unpkg.com/react@16/umd/react.development.js"
4></script>
5<script
6  crossorigin
7  src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"
8></script>
html

Since there are no modulers or transpilers, you will have to use the React.createElement() function to create a component instead of writing JSX.

1const Hello = props => React.createElement("div", null, `Hello ${props.to}!`);
js

Now, where do you render this component? Oh, that's simple you can do the following, right?

1$(document).ready(function() {
2  $("button#popover").popover({
3    html: true,
4    content: `<div id='app'></div>`
5  });
6  const Hello = props => React.createElement("div", null, `Hello ${props.to}!`);
7
8  ReactDOM.render(
9    React.createElement(Hello, { to: "World" }, null),
10    document.getElementById("app")
11  );
12});
js

Unfortunately, this won't work because the popover is initialized and the HTML content inside the popover is added by jQuery. Hence, ReactDOM.render() method will not be able to find the DOM node.

To get around this problem, create a DOM element and then access its innerHTML property inside the popover content.

1$(document).ready(function() {
2  const a = document.createElement("div");
3
4  const Hello = props => React.createElement("div", null, `Hello ${props.to}!`);
5
6  ReactDOM.render(React.createElement(Hello, { to: "World" }, null), a);
7
8  $("button#popover").popover({
9    html: true,
10    content: a.innerHTML
11  });
12});
js

If you want to display a static component, then this will work for you. But if you need interactivity inside the popover, that's something not possible with Bootstrap currently. Bootstrap does not have proper hooks to facilitate interactive behavior.

But if this was a bundled project with a transpiler, we could use the reactstrap library to add interactivity inside the popover component.

Projects with Reactstrap Library

Add reactstrap, bootstrap, and jquery in your dependencies.

1npm i reactstrap bootstrap jquery
console

In the main file, create a basic popover .

1// ...
2import "bootstrap/dist/css/bootstrap.min.css";
3import { Button, Popover, PopoverHeader, PopoverBody } from "reactstrap";
4
5const App = props => {
6  const [popoverOpen, setPopoverOpen] = useState(false);
7
8  const toggle = () => setPopoverOpen(!popoverOpen);
9
10  return (
11    <div
12      className="d-flex align-items-center justify-content-center"
13      style={{ height: "100vh" }}
14    >
15      <Button id="Popover1" type="button" color="primary">
16        Launch Popover
17      </Button>
18      <Popover
19        placement="bottom"
20        isOpen={popoverOpen}
21        target="Popover1"
22        toggle={toggle}
23      >
24        <PopoverHeader>Popover Title</PopoverHeader>
25        <PopoverBody>This the Popover body</PopoverBody>
26      </Popover>
27    </div>
28  );
29};
30// ...
jsx

Reactstrap's <Popover /> component allows you to have React components as the children. This means that the children can have state of their own and can provide interactive behavior.

Let's add a <Counter /> component, inside which there will be a <Button /> component that will increment the counter.

1// ...
2const Counter = () => {
3  const [counter, setCounter] = useState(0);
4
5  return (
6    <div>
7      <Button onClick={() => setCounter(counter + 1)}>Click</Button>
8
9      <span className="ml-3">{counter}</span>
10    </div>
11  );
12};
13// ...
jsx

Inside the <PopoverBody /> component, call the counter.

1<PopoverBody>This the Popover body</PopoverBody>
jsx

Now, when you click on the popover button, it displays the Popover component with a counter embedded inside of it .

Final result

Putting it all together, you'll have the components as follows.

1import React, { useState } from "react";
2import "./styles.css";
3import "bootstrap/dist/css/bootstrap.min.css";
4import { Button, Popover, PopoverHeader, PopoverBody } from "reactstrap";
5
6const Counter = () => {
7  const [counter, setCounter] = useState(0);
8
9  return (
10    <div>
11      <Button onClick={() => setCounter(counter + 1)}>Click</Button>
12
13      <span className="ml-3">{counter}</span>
14    </div>
15  );
16};
17
18const App = props => {
19  const [popoverOpen, setPopoverOpen] = useState(false);
20
21  const toggle = () => setPopoverOpen(!popoverOpen);
22
23  return (
24    <div
25      className="d-flex align-items-center justify-content-center"
26      style={{ height: "100vh" }}
27    >
28      <Button id="Popover1" type="button" color="primary">
29        Launch Popover
30      </Button>
31      <Popover
32        placement="bottom"
33        isOpen={popoverOpen}
34        target="Popover1"
35        toggle={toggle}
36      >
37        <PopoverHeader>Popover Title</PopoverHeader>
38        <PopoverBody>
39          <Counter />
40        </PopoverBody>
41      </Popover>
42    </div>
43  );
44};
45
46export default App;
jsx

Conclusion

This guide showed you how to add a static React component inside a bootstrap popover and how to add interactivity to the popover using a more refined library like reactstrap. These methods will come handy when you are limited by the libraries used in your project. Nevertheless, ensure that you always create a bundled project using templates like create-react-app to avoid fuzzy hacks in the end.