Tippy.js for React
The complete tooltip and popover solution for React apps
Tippy.js is a highly customizable tooltip
and popover library powered by Popper.js. This is a lightweight wrapper that
lets you use it declaratively in React.
💎 Examples
Tooltips
Popovers
🚀 Installation
npm i @tippy.js/react
yarn add @tippy.js/react
CDN: https://unpkg.com/@tippy.js/react
Requires React 16.8+
🖲 Usage
Import the Tippy
component and the core CSS. Wrap the <Tippy />
component
around the element, supplying the tooltip's content as the content
prop. It
can take a string or a tree of React elements.
import React from 'react';
import Tippy from '@tippy.js/react';
import 'tippy.js/dist/tippy.css';
const StringContent = () => (
<Tippy content="Hello">
<button>My button</button>
</Tippy>
);
const JSXContent = () => (
<Tippy content={<span>Tooltip</span>}>
<button>My button</button>
</Tippy>
);
Component children
If you want to use a component element as a child, ensure you forward the ref to
the DOM node:
import React, {forwardRef} from 'react';
function ThisWontWork() {
return <button>Text</button>;
}
const ThisWillWork = forwardRef((props, ref) => {
return <button ref={ref}>Text</button>;
});
function App() {
return (
<Tippy content="Tooltip">
<ThisWillWork />
</Tippy>
);
}
styled-components
v4 does this for you automatically, so it should be seamless
when using the styled
constructor.
If you're using a library that doesn't forwardRef
for you, and doesn't give
access to the ref via innerRef
or similar, you can use a wrapper <span>
element as a workaround.
<Tippy content="Tooltip">
<span tabIndex="0">
<LegacyComponent>Content</LegacyComponent>
</span>
</Tippy>
🧬 Props
All of the native Tippy.js props can be passed to the component.
Visit All Props to view the
complete table.
<Tippy
content="Tooltip"
arrow={true}
animation="scale"
duration={0}
delay={[300, 0]}
>
<button>Text</button>
</Tippy>
In addition, there are 3 more props added specifically for the React component.
className?: string
A React alternative to the theme
prop. The className gets added to the tooltip
element's class list as expected, without adding -theme
as a suffix.
<Tippy content="Tooltip" className="hello world">
<button />
</Tippy>
If you're using styled-components
, the className
prop allows you to avoid
global styles with the following technique:
const PurpleTippy = styled(Tippy)`
background: purple;
/* Styling the arrow for different placements */
&[data-placement^='top'] {
.tippy-arrow {
border-top-color: purple;
}
}
`;
See themes for more information.
Note: the following examples are using the new
React Hooks API. It isn't
required to use this library – the props will work as expected in class
components too.
enabled?: boolean
Prop to control the tippy.enable()
/ tippy.disable()
instance methods. Use
this when you want to temporarily disable a tippy from showing.
function App() {
const [enabled, setEnabled] = useState(true);
return (
<Tippy content="Tooltip" enabled={enabled}>
<button />
</Tippy>
);
}
visible?: boolean
Prop to control the tippy.show()
/ tippy.hide()
instance methods. Use this
when you want to programmatically show or hide the tippy instead of relying on
UI events. This puts the tippy in controlled mode so it will only respond to
state.
function App() {
const [visible, setVisible] = useState(true);
return (
<Tippy content="Tooltip" visible={visible}>
<button />
</Tippy>
);
}
Note: You should also set the hideOnClick
prop to false
if you don't
want the tippy to hide when the user clicks on the document somewhere.
Plugins
Tippy.js splits certain props into separate pieces of code called plugins to
enable treeshaking, so that users who don't need the prop's functionality are
not burdened with the cost of it.
import Tippy from '@tippy.js/react';
import {followCursor} from 'tippy.js';
import 'tippy.js/dist/tippy.css';
function App() {
return (
<Tippy content="Tooltip" followCursor={true} plugins={[followCursor]}>
<button />
</Tippy>
);
}
Read more about plugins here.
Performance
Props that the popperInstance
depends on that aren't primitive values should be memoized or hoisted to a static constant, so that the popperInstance
is not recreated on every render:
popperOptions
flipBehavior
const popperOptions = {};
function App() {
const [placement, setPlacement] = useState('right');
const flipBehavior = useMemo(() => [placement, 'bottom'], [placement]);
return (
<Tippy
content="Tooltip"
placement={placement}
flipBehavior={flipBehavior}
popperOptions={popperOptions}
>
<button />
</Tippy>
);
}
Default props
You can create a new component file that exports a wrapper component that has
its own default props.
import Tippy from '@tippy.js/react';
export default props => <Tippy animation="fade" {...props} />;
Proxy components
<Tippy />
's purpose is to be a useful generic component for all types of
popper elements. This includes tooltips, popovers, dropdowns, etc. This means
you can create proxy components that wrap the base <Tippy />
component with a
new name and their own default props, to distinguish their functionality. For
example:
export function Tooltip(props) {
return (
<Tippy
animation="fade"
theme="translucent"
arrow={true}
delay={150}
{...props}
/>
);
}
export function Popover(props) {
return (
<Tippy
interactive={true}
interactiveBorder={10}
animation="scale"
theme="light-border"
trigger="click"
{...props}
/>
);
}
import {Tooltip, Popover} from './Tippy';
🌈 Multiple tippys on a single element
You can nest the components like so:
<Tippy content="Tooltip" placement="bottom">
<Tippy content="Tooltip" placement="left">
<Tippy content="Tooltip" placement="right">
<Tippy content="Tooltip">
<button />
</Tippy>
</Tippy>
</Tippy>
</Tippy>
📚 Singleton
Wraps the
createSingleton()
method.
Depending on your component tree, you can use one of the following:
<TippySingleton />
If each of your reference elements are adjacent to one another, with no nesting in the tree.
import Tippy, {TippySingleton} from '@tippy.js/react';
function App() {
return (
<TippySingleton delay={500}>
<Tippy content="a">
<button />
</Tippy>
<Tippy content="b">
<button />
</Tippy>
</TippySingleton>
);
}
useSingleton()
(v3.1)
If each of your reference elements are not adjacent to one another, or there is nesting in the tree.
import Tippy, {useSingleton} from '@tippy.js/react';
function App() {
const singleton = useSingleton({delay: 500});
return (
<>
<Tippy content="a" singleton={singleton}>
<button />
</Tippy>
<button />
<div>
<Tippy content="b" singleton={singleton}>
<button />
</Tippy>
</div>
</>
);
}
📦 Bundle size
popper.js
≈ 7 kBtippy.js
≈ 5.5 kB (including CSS)@tippy.js/react
≈ 1 kB
If you're using Popper.js for other parts of your app, the added cost becomes
much smaller!
⭐️ Comparison with other tooltip/popover libraries
Why should you use this library, and how does it compare to other ones?
Read all about it here!
📝 License
MIT