A set of components for positioning beautiful overlays, tooltips, popovers, and anything else you need.
Overview
Things to know about the React-Bootstrap Overlay components.
- Overlays rely on the third-party library Popper.js.
It's included automatically with React-Bootstrap, but you should reference the API
for more advanced use cases.
- The
<Tooltip>
and <Popover>
components do not position themselves. Instead the
<Overlay>
(or <OverlayTrigger>
) components, inject ref
and style
props.
- Tooltip expects specific props injected by the
<Overlay>
component.
- Tooltips for
disabled
elements must be triggered on a wrapper element.
Overlay
Overlay
is the fundamental component for positioning and
controlling tooltip visibility. It's a wrapper around Popper.js, that
adds support for transitions, and visibility toggling.
Creating an Overlay
Overlays consist of at least two elements, the "overlay", the element to
be positioned, as well as a "target", the element the overlay is
positioned in relation to. You can also have an "arrow" element,
like the tooltips and popovers, but that is optional. Be sure to
check out the Popper
documentation for more details about the injected props.
import { useState, useRef } from 'react';
import Button from 'react-bootstrap/Button';
import Overlay from 'react-bootstrap/Overlay';
function Example() {
const [show, setShow] = useState(false);
const target = useRef(null);
return (
<>
<Button variant="danger" ref={target} onClick={() => setShow(!show)}>
Click me to see
</Button>
<Overlay target={target.current} show={show} placement="right">
{({
placement: _placement,
arrowProps: _arrowProps,
show: _show,
popper: _popper,
hasDoneInitialMeasure: _hasDoneInitialMeasure,
...props
}) => (
<div
{...props}
style={{
position: 'absolute',
backgroundColor: 'rgba(255, 100, 100, 0.85)',
padding: '2px 10px',
color: 'white',
borderRadius: 3,
...props.style,
}}
>
Simple tooltip
</div>
)}
</Overlay>
</>
);
}
export default Example;
Customizing Overlay rendering
The Overlay
injects a number of props that you can use to customize the
rendering behavior. There is a case where you would need to show the overlay
before Popper
can measure and position it properly. In React-Bootstrap,
tooltips and popovers sets the opacity and position to avoid issues where
the initial positioning of the overlay is incorrect. See the
Tooltip
implementation for an example on how this is done.
OverlayTrigger
Since the above pattern is pretty common, but verbose, we've included
<OverlayTrigger>
component to help with common
use-cases. It even has functionality to delayed show or hides, and a few
different "trigger" events you can mix and match.
Note that triggering components must be able to accept a ref
since <OverlayTrigger>
will attempt to add one. You can use
forwardRef() for function components.
import Button from 'react-bootstrap/Button';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Tooltip from 'react-bootstrap/Tooltip';
function TriggerExample() {
const renderTooltip = (props) => (
<Tooltip id="button-tooltip" {...props}>
Simple tooltip
</Tooltip>
);
return (
<OverlayTrigger
placement="right"
delay={{ show: 250, hide: 400 }}
overlay={renderTooltip}
>
<Button variant="success">Hover me to see</Button>
</OverlayTrigger>
);
}
export default TriggerExample;
Customizing trigger behavior
For more advanced behaviors <OverlayTrigger>
accepts a
function child that passes in the injected ref
and event
handlers that correspond to the configured trigger
prop.
You can manually apply the props to any element you want or split them
up. The example below shows how to position the overlay to a different
element than the one that triggers its visibility.
Using the function form of OverlayTrigger avoids a
React.findDOMNode
call, for those trying to be strict mode
compliant.
import Button from 'react-bootstrap/Button';
import Image from 'react-bootstrap/Image';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
function TriggerRendererProp() {
return (
<OverlayTrigger
placement="bottom"
overlay={<Tooltip id="button-tooltip-2">Check out this avatar</Tooltip>}
>
{({ ref, ...triggerHandler }) => (
<Button
variant="light"
{...triggerHandler}
className="d-inline-flex align-items-center"
>
<Image
ref={ref}
roundedCircle
src="holder.js/20x20?text=J&bg=28a745&fg=FFF"
/>
<span className="ms-1">Hover to see</span>
</Button>
)}
</OverlayTrigger>
);
}
export default TriggerRendererProp;
A tooltip component for a more stylish alternative to that anchor tag
title
attribute.
Examples
Hover over the links below to see tooltips.
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Tooltip from 'react-bootstrap/Tooltip';
function TooltipInCopyExample() {
const Link = ({ id, children, title }) => (
<OverlayTrigger overlay={<Tooltip id={id}>{title}</Tooltip>}>
<a href="#">{children}</a>
</OverlayTrigger>
);
return (
<p>
Tight pants next level keffiyeh{' '}
<Link title="Default title" id="t-1">
you probably
</Link>{' '}
haven't heard of them. Farm-to-table seitan, mcsweeney's fixie sustainable
quinoa 8-bit american apparel{' '}
<Link id="t-2" title="Another one">
have a
</Link>{' '}
terry richardson vinyl chambray. Beard stumptown, cardigans banh mi lomo
thundercats. Tofu biodiesel williamsburg marfa, four loko mcsweeney's
cleanse vegan chambray. A really ironic artisan{' '}
<Link title="Another one here too" id="t-3">
whatever keytar
</Link>
, scenester farm-to-table banksy Austin{' '}
<Link title="The last tip!" id="t-4">
twitter handle
</Link>{' '}
freegan cred raw denim single-origin coffee viral.
</p>
);
}
export default TooltipInCopyExample;
You can pass the Overlay
injected props directly to the
Tooltip component.
import { useState, useRef } from 'react';
import Button from 'react-bootstrap/Button';
import Overlay from 'react-bootstrap/Overlay';
import Tooltip from 'react-bootstrap/Tooltip';
function Example() {
const [show, setShow] = useState(false);
const target = useRef(null);
return (
<>
<Button ref={target} onClick={() => setShow(!show)}>
Click me!
</Button>
<Overlay target={target.current} show={show} placement="right">
{(props) => (
<Tooltip id="overlay-example" {...props}>
My Tooltip
</Tooltip>
)}
</Overlay>
</>
);
}
export default Example;
Or pass a Tooltip element to OverlayTrigger
instead.
import Button from 'react-bootstrap/Button';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Tooltip from 'react-bootstrap/Tooltip';
function TooltipPositionedExample() {
return (
<>
{['top', 'right', 'bottom', 'left'].map((placement) => (
<OverlayTrigger
key={placement}
placement={placement}
overlay={
<Tooltip id={`tooltip-${placement}`}>
Tooltip on <strong>{placement}</strong>.
</Tooltip>
}
>
<Button variant="secondary">Tooltip on {placement}</Button>
</OverlayTrigger>
))}
</>
);
}
export default TooltipPositionedExample;
Popovers
A popover component, like those found in iOS.
Examples
import Button from 'react-bootstrap/Button';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Popover from 'react-bootstrap/Popover';
const popover = (
<Popover id="popover-basic">
<Popover.Header as="h3">Popover right</Popover.Header>
<Popover.Body>
And here's some <strong>amazing</strong> content. It's very engaging.
right?
</Popover.Body>
</Popover>
);
const Example = () => (
<OverlayTrigger trigger="click" placement="right" overlay={popover}>
<Button variant="success">Click me to see</Button>
</OverlayTrigger>
);
render(<Example />);
As with <Tooltip>
s, you can control the placement of the Popover.
import Button from 'react-bootstrap/Button';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Popover from 'react-bootstrap/Popover';
function PopoverPositionedExample() {
return (
<>
{['top', 'right', 'bottom', 'left'].map((placement) => (
<OverlayTrigger
trigger="click"
key={placement}
placement={placement}
overlay={
<Popover id={`popover-positioned-${placement}`}>
<Popover.Header as="h3">{`Popover ${placement}`}</Popover.Header>
<Popover.Body>
<strong>Holy guacamole!</strong> Check this info.
</Popover.Body>
</Popover>
}
>
<Button variant="secondary">Popover on {placement}</Button>
</OverlayTrigger>
))}
</>
);
}
export default PopoverPositionedExample;
Disabled elements
Elements with the disabled
attribute aren’t interactive,
meaning users cannot hover or click them to trigger a popover (or
tooltip). As a workaround, you’ll want to trigger the overlay from a
wrapper <div>
or <span>
and override the pointer-events
on the
disabled element.
import Button from 'react-bootstrap/Button';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Tooltip from 'react-bootstrap/Tooltip';
function DisabledExample() {
return (
<OverlayTrigger overlay={<Tooltip id="tooltip-disabled">Tooltip!</Tooltip>}>
<span className="d-inline-block">
<Button disabled style={{ pointerEvents: 'none' }}>
Disabled button
</Button>
</span>
</OverlayTrigger>
);
}
export default DisabledExample;
Changing containers
You can specify a container
to control the DOM element the
overlay is appended to. This is especially useful when styles conflict
with your Overlays.
import { useState, useRef } from 'react';
import Button from 'react-bootstrap/Button';
import Overlay from 'react-bootstrap/Overlay';
import Popover from 'react-bootstrap/Popover';
function Example() {
const [show, setShow] = useState(false);
const [target, setTarget] = useState(null);
const ref = useRef(null);
const handleClick = (event) => {
setShow(!show);
setTarget(event.target);
};
return (
<div ref={ref}>
<Button onClick={handleClick}>Holy guacamole!</Button>
<Overlay
show={show}
target={target}
placement="bottom"
container={ref}
containerPadding={20}
>
<Popover id="popover-contained">
<Popover.Header as="h3">Popover bottom</Popover.Header>
<Popover.Body>
<strong>Holy guacamole!</strong> Check this info.
</Popover.Body>
</Popover>
</Overlay>
</div>
);
}
export default Example;
Updating position dynamically
Since we can't know every time your overlay changes size, to reposition
it, you need to take manual action if you want to update the position of
an Overlay in response to a change.
For this, the Overlay component also injects a popper
prop with a scheduleUpdate()
method that an overlay
component can use to reposition itself.
import React, { useEffect, useState } from 'react';
import Button from 'react-bootstrap/Button';
import OverlayTrigger from 'react-bootstrap/OverlayTrigger';
import Popover from 'react-bootstrap/Popover';
const UpdatingPopover = React.forwardRef(
({ popper, children, show: _, ...props }, ref) => {
useEffect(() => {
console.log('updating!');
popper.scheduleUpdate();
}, [children, popper]);
return (
<Popover ref={ref} body {...props}>
{children}
</Popover>
);
},
);
const longContent = `
Very long
Multiline content
that is engaging and what-not
`;
const shortContent = 'Short and sweet!';
function Example() {
const [content, setContent] = useState(shortContent);
useEffect(() => {
const timerId = setInterval(() => {
setContent(content === shortContent ? longContent : shortContent);
}, 3000);
return () => clearInterval(timerId);
});
return (
<OverlayTrigger
trigger="click"
overlay={
<UpdatingPopover id="popover-contained">{content}</UpdatingPopover>
}
>
<Button>Holy guacamole!</Button>
</OverlayTrigger>
);
}
render(<Example />);
API
Overlay
OverlayTrigger
Popover
PopoverBody