JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 592607
  • Score
    100M100P100Q177311F
  • License MIT

React component for Tippy.js

Package Exports

  • @tippyjs/react
  • @tippyjs/react/headless

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@tippyjs/react) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Logo

Tippy.js for React

Tippy.js is the complete tooltip, popover, dropdown, and menu solution for the web, powered by Popper.js. It provides the logic and styling involved in all types of elements that pop out from the flow of the document and get overlaid on top of the UI, positioned next to a reference element.

This is a lightweight wrapper that lets you use it declaratively in React.

🚀 Installation

# npm
npm i @tippyjs/react

# Yarn
yarn add @tippyjs/react

CDN: https://unpkg.com/@tippyjs/react

Requires React 16.8+

🖲 Usage

There are two ways to use this component:

  • Default: With the built-in DOM rendering and optionally the default CSS
  • Headless: With React's DOM rendering for better usage with CSS-in-JS and spring libraries e.g. react-spring

Default Tippy

Import the Tippy component and (optionally) 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 '@tippyjs/react';
import 'tippy.js/dist/tippy.css'; // optional

const StringContent = () => (
  <Tippy content="Hello">
    <button>My button</button>
  </Tippy>
);

const JSXContent = () => (
  <Tippy content={<span>Tooltip</span>}>
    <button>My button</button>
  </Tippy>
);

Default Tippy is very quick to use and setup and "just works" out of the box.

Headless Tippy

Render your own tippy element from scratch:

import React from 'react';
import Tippy from '@tippyjs/react/headless';

const HeadlessTippy = () => (
  <Tippy
    render={attrs => (
      <div className="box" {...attrs}>
        My tippy box
      </div>
    )}
  >
    <button>My button</button>
  </Tippy>
);

attrs is an object containing data-placement, data-reference-hidden, and data-escaped attributes. This allows you to conditionally style your tippy if necessary.

A more advanced example using react-spring & styled-components:

import React from 'react';
import Tippy from '@tippyjs/react/headless';
import styled from 'styled-components';
import {useSpring, animated} from 'react-spring';

const Box = styled(animated.div)`
  background: #333;
  color: white;
  padding: 5px 10px;
  border-radius: 4px;
`;

function AnimatedHeadlessTippy() {
  const config = {tension: 300, friction: 15};
  const initialStyles = {opacity: 0, transform: 'scale(0.5)'};
  const [props, setSpring] = useSpring(() => initialStyles);

  function onMount() {
    setSpring({
      opacity: 1,
      transform: 'scale(1)',
      onRest: () => {},
      config,
    });
  }

  function onHide({unmount}) {
    setSpring({
      ...initialStyles,
      onRest: unmount,
      config: {...config, clamp: true},
    });
  }

  return (
    <Tippy
      render={attrs => (
        <Box style={props} {...attrs}>
          Hello
        </Box>
      )}
      animation={true}
      onMount={onMount}
      onHide={onHide}
    >
      <button>react-spring</button>
    </Tippy>
  );
}

Arrow

To make Popper position your custom arrow, set a data-popper-arrow attribute on it:

<Tippy
  render={attrs => (
    <Box {...attrs}>
      Hello
      <Arrow data-popper-arrow="" />
    </Box>
  )}
>
  <button>Reference</button>
</Tippy>

For details on styling the arrow from scratch, take a look at the Popper tutorial.

You may also pass a ref to the element directly without the attribute using a callback ref:

function App() {
  const [arrow, setArrow] = useState(null);

  return (
    <Tippy
      render={attrs => (
        <Box {...attrs}>
          Content
          <Arrow ref={setArrow} />
        </Box>
      )}
      popperOptions={{
        modifiers: [
          {
            name: 'arrow',
            options: {
              element: arrow,
            },
          },
        ],
      }}
    >
      <button>Reference</button>
    </Tippy>
  );
}

Note on Headless Tippy in React

The root popper node is abstracted away and gets styled/mutated by Tippy internally, so Headless Tippy in React is partially headless. This ensures it works correctly with minimal effort on your behalf to render.

When rendering an element with the render prop, you're rendering the inner box element that the root popper node wraps, which is what gets styled and animated. For advanced cases, you can access the parent popper node as instance.popper in the onCreate lifecycle hook.

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>Reference</button>;
}

const ThisWillWork = forwardRef((props, ref) => {
  return <button ref={ref}>Reference</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>Reference</LegacyComponent>
  </span>
</Tippy>

🧬 Props

All of the native Tippy.js props can be passed to the component.

Visit All Props to view the complete list.

<Tippy
  content="Tooltip"
  arrow={false}
  animation="scale"
  duration={0}
  delay={[300, 0]}
  // ...and many more!
>
  <button>Reference</button>
</Tippy>

In addition, there are 3 more props added specifically for the React component.

className?: string

Note: This does not apply if using Headless Tippy

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>Reference</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::before {
    border-top-color: purple;
  }
`;

See themes for more information.

disabled?: boolean

function App() {
  const [disabled, setDisabled] = useState(false);

  return (
    <Tippy content="Tooltip" disabled={disabled}>
      <button>Reference</button>
    </Tippy>
  );
}

visible?: boolean (controlled mode)

Use React's state to fully control the tippy instead of relying on the native trigger and hideOnClick props:

function App() {
  const [visible, setVisible] = useState(true);
  const show = () => setVisible(true);
  const hide = () => setVisible(false);

  return (
    <Tippy content="Tooltip" visible={visible} onClickOutside={hide}>
      <button onClick={visible ? hide : show}>Reference</button>
    </Tippy>
  );
}

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 '@tippyjs/react';
import {followCursor} from 'tippy.js';

function App() {
  return (
    <Tippy content="Tooltip" followCursor={true} plugins={[followCursor]}>
      <button>Reference</button>
    </Tippy>
  );
}

Read more about plugins here.

🌈 Multiple tippies 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>Reference</button>
      </Tippy>
    </Tippy>
  </Tippy>
</Tippy>

📚 useSingleton

A Hook for the createSingleton() addon.

import Tippy, {useSingleton} from '@tippyjs/react';

function App() {
  const [source, target] = useSingleton();

  return (
    <>
      {/* This is the tippy that gets used as the singleton */}
      <Tippy singleton={source} delay={500} />

      {/* These become "virtual" */}
      <Tippy content="Hello" singleton={target}>
        <button>Reference</button>
      </Tippy>
      <Tippy content="Bye" singleton={target}>
        <button>Reference</button>
      </Tippy>
    </>
  );
}

useSingleton() takes an optional props argument:

const [source, target] = useSingleton({
  disabled: true,
  overrides: ['placement'],
});

Headless singleton

The render prop takes the singleton content as a second parameter:

import Tippy, {useSingleton} from '@tippyjs/react/headless';

function App() {
  const [source, target] = useSingleton();

  return (
    <>
      <Tippy
        singleton={source}
        render={(attrs, content) => (
          <div className="box" {...attrs}>
            {content}
          </div>
        )}
        delay={500}
      />

      <Tippy content="Hello" singleton={target}>
        <button>Reference</button>
      </Tippy>
      <Tippy content="Bye" singleton={target}>
        <button>Reference</button>
      </Tippy>
    </>
  );
}

📝 License

MIT