Skip to content

Tooltip

The tooltip component is a wrap over intergalactic/popper with additional features:

  • Stylization and themes for the popper.
  • Adding arrow for the popper to point to its trigger.

TIP

If you need to customize tooltip behavior, refer to intergalactic/popper documentation.

Basic usage

Use the appropriate component depending on your case. See Tooltip API and Tooltip A11y for more details.

tsx
import React from 'react';
import Tooltip, { Hint, DescriptionTooltip } from 'intergalactic/tooltip';
import { Flex } from 'intergalactic/flex-box';
import { Text, Hint as HintLink } from 'intergalactic/typography';
import Link from 'intergalactic/link';
import Button from 'intergalactic/button';
import FileExportM from 'intergalactic/icon/FileExport/m';
import CheckAltM from 'intergalactic/icon/CheckAlt/m';
import InfoM from 'intergalactic/icon/Info/m';

const Demo = () => (
  <Flex gap={4} direction='column'>
    <Flex gap={4} alignItems='center'>
      Tooltip:
      <Tooltip
        tag={Link}
        href='https://google.com'
        title='Default tooltip contains short text explaining something about the trigger.'
      >
        Keywords
      </Tooltip>
      <Tooltip
        title='Default tooltip contains short text explaining something about the trigger.'
        tag={Button}
        aria-label='Export to PDF'
        addonLeft={FileExportM}
      />
    </Flex>
    <Flex gap={4} alignItems='center'>
      Hint:
      <Hint title='Export to PDF' tag={Button} addonLeft={FileExportM} />
      <Hint
        title='You confirmed your email'
        aria-hidden={false}
        tag={CheckAltM}
        color='var(--intergalactic-icon-primary-success)'
      />
    </Flex>
    <Flex gap={4} alignItems='center'>
      DescriptionTooltip:
      <DescriptionTooltip>
        <DescriptionTooltip.Trigger tag={HintLink}>
          About fastest animals
        </DescriptionTooltip.Trigger>
        <DescriptionTooltip.Popper aria-label='About fastest animals'>
          <Text tag='p' mb={3}>
            The <Link href='https://en.wikipedia.org/wiki/Peregrine_falcon'>peregrine falcon</Link>{' '}
            is the fastest bird, and the fastest member of the animal kingdom, with a diving speed
            of over 300 km/h (190 mph).
          </Text>
          <Text tag='p'>
            The fastest land animal is the cheetah. Among the fastest animals in the sea is the
            black marlin, with uncertain and conflicting reports of recorded speeds.
          </Text>
        </DescriptionTooltip.Popper>
      </DescriptionTooltip>
      <DescriptionTooltip>
        <DescriptionTooltip.Trigger
          tag={InfoM}
          color='var(--intergalactic-icon-secondary-neutral)'
          interactive
          aria-label='About peregrine falcon'
        />
        <DescriptionTooltip.Popper aria-label='About peregrine falcon'>
          <Text tag='p' mb={3}>
            The peregrine falcon is the fastest aerial animal, fastest animal in flight, fastest
            bird, and the overall fastest member of the{' '}
            <Link href='https://en.wikipedia.org/wiki/Animal'>animal kingdom</Link>.
          </Text>
          <Text tag='p'>
            The peregrine achieves its highest velocity not in horizontal level flight, but during
            its characteristic hunting stoop (vertical flight). While stooping, the peregrine falcon
            soars to a great height, then dives steeply at speed of over 320 km/h (200 mph).
          </Text>
        </DescriptionTooltip.Popper>
      </DescriptionTooltip>
    </Flex>
  </Flex>
);

export default Demo;
import React from 'react';
import Tooltip, { Hint, DescriptionTooltip } from 'intergalactic/tooltip';
import { Flex } from 'intergalactic/flex-box';
import { Text, Hint as HintLink } from 'intergalactic/typography';
import Link from 'intergalactic/link';
import Button from 'intergalactic/button';
import FileExportM from 'intergalactic/icon/FileExport/m';
import CheckAltM from 'intergalactic/icon/CheckAlt/m';
import InfoM from 'intergalactic/icon/Info/m';

const Demo = () => (
  <Flex gap={4} direction='column'>
    <Flex gap={4} alignItems='center'>
      Tooltip:
      <Tooltip
        tag={Link}
        href='https://google.com'
        title='Default tooltip contains short text explaining something about the trigger.'
      >
        Keywords
      </Tooltip>
      <Tooltip
        title='Default tooltip contains short text explaining something about the trigger.'
        tag={Button}
        aria-label='Export to PDF'
        addonLeft={FileExportM}
      />
    </Flex>
    <Flex gap={4} alignItems='center'>
      Hint:
      <Hint title='Export to PDF' tag={Button} addonLeft={FileExportM} />
      <Hint
        title='You confirmed your email'
        aria-hidden={false}
        tag={CheckAltM}
        color='var(--intergalactic-icon-primary-success)'
      />
    </Flex>
    <Flex gap={4} alignItems='center'>
      DescriptionTooltip:
      <DescriptionTooltip>
        <DescriptionTooltip.Trigger tag={HintLink}>
          About fastest animals
        </DescriptionTooltip.Trigger>
        <DescriptionTooltip.Popper aria-label='About fastest animals'>
          <Text tag='p' mb={3}>
            The <Link href='https://en.wikipedia.org/wiki/Peregrine_falcon'>peregrine falcon</Link>{' '}
            is the fastest bird, and the fastest member of the animal kingdom, with a diving speed
            of over 300 km/h (190 mph).
          </Text>
          <Text tag='p'>
            The fastest land animal is the cheetah. Among the fastest animals in the sea is the
            black marlin, with uncertain and conflicting reports of recorded speeds.
          </Text>
        </DescriptionTooltip.Popper>
      </DescriptionTooltip>
      <DescriptionTooltip>
        <DescriptionTooltip.Trigger
          tag={InfoM}
          color='var(--intergalactic-icon-secondary-neutral)'
          interactive
          aria-label='About peregrine falcon'
        />
        <DescriptionTooltip.Popper aria-label='About peregrine falcon'>
          <Text tag='p' mb={3}>
            The peregrine falcon is the fastest aerial animal, fastest animal in flight, fastest
            bird, and the overall fastest member of the{' '}
            <Link href='https://en.wikipedia.org/wiki/Animal'>animal kingdom</Link>.
          </Text>
          <Text tag='p'>
            The peregrine achieves its highest velocity not in horizontal level flight, but during
            its characteristic hunting stoop (vertical flight). While stooping, the peregrine falcon
            soars to a great height, then dives steeply at speed of over 320 km/h (200 mph).
          </Text>
        </DescriptionTooltip.Popper>
      </DescriptionTooltip>
    </Flex>
  </Flex>
);

export default Demo;

Nested trigger accessibility

This example shows how to ensure accessibility if you decide to nest focusable elements instead of merging them with Trigger. Read more about Tooltip accessibility.

tsx
import React from 'react';
import Tooltip from 'intergalactic/tooltip';
import { Box, Flex } from 'intergalactic/flex-box';
import Link from 'intergalactic/link';

const Demo = () => (
  <Flex>
    <Box m='auto' p={5}>
      <Tooltip>
        <Tooltip.Trigger aria-describedby={undefined} role={undefined}>
          {({ popperId }) => <Link aria-describedby={popperId}>Tooltip trigger</Link>}
        </Tooltip.Trigger>
        <Tooltip.Popper>Hello, stranger!</Tooltip.Popper>
      </Tooltip>
    </Box>
  </Flex>
);

export default Demo;
import React from 'react';
import Tooltip from 'intergalactic/tooltip';
import { Box, Flex } from 'intergalactic/flex-box';
import Link from 'intergalactic/link';

const Demo = () => (
  <Flex>
    <Box m='auto' p={5}>
      <Tooltip>
        <Tooltip.Trigger aria-describedby={undefined} role={undefined}>
          {({ popperId }) => <Link aria-describedby={popperId}>Tooltip trigger</Link>}
        </Tooltip.Trigger>
        <Tooltip.Popper>Hello, stranger!</Tooltip.Popper>
      </Tooltip>
    </Box>
  </Flex>
);

export default Demo;

Singleton

You can use a single tooltip for multiple reference elements. This allows you to "group" tooltips with a shared timer to improve the user experience. This example uses React context and memo to bypass select component rerendering and much improve performance during quick navigation.

tsx
import React from 'react';
import Tooltip from 'intergalactic/tooltip';
import Select from 'intergalactic/select';
import { Text } from 'intergalactic/typography';
import { Flex } from 'intergalactic/flex-box';

const options = Array(50)
  .fill('')
  .map((_, index) => `Option ${index}`);

const tooltipIndexContext = React.createContext(0);

const TooltipContent = () => {
  const tooltipIndex = React.useContext(tooltipIndexContext);
  return <>Option {tooltipIndex} description</>;
};

const SelectWithTooltip = React.memo(
  ({ setTooltipIndex }: { setTooltipIndex: (number) => void }) => {
    return (
      <Flex direction='column'>
        <Text tag='label' size={200} htmlFor='select-with-tooltips'>
          Select with tooltips
        </Text>
        <Select onHighlightedIndexChange={setTooltipIndex}>
          <Select.Trigger placeholder='Select option' mt={2} mr='auto' id='select-with-tooltips' />
          <Select.Menu>
            <Tooltip timeout={[0, 50]} placement='right'>
              {options.map((option, index) => (
                <Select.Option
                  onMouseEnter={() => setTooltipIndex(index)}
                  value={option}
                  key={index}
                  tag={Tooltip.Trigger}
                >
                  {option}
                </Select.Option>
              ))}
              <Tooltip.Popper w={200}>
                <TooltipContent />
              </Tooltip.Popper>
            </Tooltip>
          </Select.Menu>
        </Select>
      </Flex>
    );
  },
  () => true,
);

const Demo = () => {
  const [tooltipIndex, setTooltipIndex] = React.useState(0);

  return (
    <tooltipIndexContext.Provider value={tooltipIndex}>
      <SelectWithTooltip setTooltipIndex={setTooltipIndex} />
    </tooltipIndexContext.Provider>
  );
};

export default Demo;
import React from 'react';
import Tooltip from 'intergalactic/tooltip';
import Select from 'intergalactic/select';
import { Text } from 'intergalactic/typography';
import { Flex } from 'intergalactic/flex-box';

const options = Array(50)
  .fill('')
  .map((_, index) => `Option ${index}`);

const tooltipIndexContext = React.createContext(0);

const TooltipContent = () => {
  const tooltipIndex = React.useContext(tooltipIndexContext);
  return <>Option {tooltipIndex} description</>;
};

const SelectWithTooltip = React.memo(
  ({ setTooltipIndex }: { setTooltipIndex: (number) => void }) => {
    return (
      <Flex direction='column'>
        <Text tag='label' size={200} htmlFor='select-with-tooltips'>
          Select with tooltips
        </Text>
        <Select onHighlightedIndexChange={setTooltipIndex}>
          <Select.Trigger placeholder='Select option' mt={2} mr='auto' id='select-with-tooltips' />
          <Select.Menu>
            <Tooltip timeout={[0, 50]} placement='right'>
              {options.map((option, index) => (
                <Select.Option
                  onMouseEnter={() => setTooltipIndex(index)}
                  value={option}
                  key={index}
                  tag={Tooltip.Trigger}
                >
                  {option}
                </Select.Option>
              ))}
              <Tooltip.Popper w={200}>
                <TooltipContent />
              </Tooltip.Popper>
            </Tooltip>
          </Select.Menu>
        </Select>
      </Flex>
    );
  },
  () => true,
);

const Demo = () => {
  const [tooltipIndex, setTooltipIndex] = React.useState(0);

  return (
    <tooltipIndexContext.Provider value={tooltipIndex}>
      <SelectWithTooltip setTooltipIndex={setTooltipIndex} />
    </tooltipIndexContext.Provider>
  );
};

export default Demo;

Ignore portal stacking

By default, when a tooltip is rendered on the edge of a relatively positioned block, the popup mechanism may try to push it inside the block as much as possible. If you don't want this behavior, you can set the ignorePortalsStacking prop.

tsx
import React from 'react';
import Button from 'intergalactic/button';
import Modal from 'intergalactic/modal';
import { Text } from 'intergalactic/typography';
import { Box } from 'intergalactic/flex-box';
import Input from 'intergalactic/input';
import Tooltip from 'intergalactic/tooltip';

const Demo = () => {
  const [visible, setVisible] = React.useState(false);

  return (
    <React.Fragment>
      <Button onClick={() => setVisible(true)}>Open modal</Button>
      <Modal visible={visible} onClose={() => setVisible(false)} w={536}>
        <Box mb={2}>
          <Text size={300} tag='label' htmlFor='input-1'>
            First input with tooltip
          </Text>
        </Box>
        <Tooltip
          title='Tooltip with ignoring portals stacking.'
          visible={true}
          placement='left-start'
          ignorePortalsStacking
        >
          <Input size='l' w={440}>
            <Input.Value id='input-2' />
          </Input>
        </Tooltip>
        <Box mt={5} mb={2}>
          <Text size={300} tag='label' htmlFor='input-2'>
            Second input with tooltip
          </Text>
        </Box>
        <Tooltip
          title='Tooltip without ignoring portals stacking.'
          visible={true}
          placement='right-start'
        >
          <Input size='l' w={440}>
            <Input.Value id='input-2' />
          </Input>
        </Tooltip>
      </Modal>
    </React.Fragment>
  );
};

export default Demo;
import React from 'react';
import Button from 'intergalactic/button';
import Modal from 'intergalactic/modal';
import { Text } from 'intergalactic/typography';
import { Box } from 'intergalactic/flex-box';
import Input from 'intergalactic/input';
import Tooltip from 'intergalactic/tooltip';

const Demo = () => {
  const [visible, setVisible] = React.useState(false);

  return (
    <React.Fragment>
      <Button onClick={() => setVisible(true)}>Open modal</Button>
      <Modal visible={visible} onClose={() => setVisible(false)} w={536}>
        <Box mb={2}>
          <Text size={300} tag='label' htmlFor='input-1'>
            First input with tooltip
          </Text>
        </Box>
        <Tooltip
          title='Tooltip with ignoring portals stacking.'
          visible={true}
          placement='left-start'
          ignorePortalsStacking
        >
          <Input size='l' w={440}>
            <Input.Value id='input-2' />
          </Input>
        </Tooltip>
        <Box mt={5} mb={2}>
          <Text size={300} tag='label' htmlFor='input-2'>
            Second input with tooltip
          </Text>
        </Box>
        <Tooltip
          title='Tooltip without ignoring portals stacking.'
          visible={true}
          placement='right-start'
        >
          <Input size='l' w={440}>
            <Input.Value id='input-2' />
          </Input>
        </Tooltip>
      </Modal>
    </React.Fragment>
  );
};

export default Demo;

Custom colors for background and arrow

For some specific cases, you can color the Tooltip's arrow using the arrowBgColor property for its background and the arrowShadowColor property for its border. For example, if you have a colored illustration placed at the bottom of the Tooltip content, you might want to color the arrow to match the illustration's color.

tsx
import React from 'react';
import Tooltip from 'intergalactic/tooltip';
import { Box } from 'intergalactic/flex-box';
import Link from 'intergalactic/link';

const Demo = () => (
  <Tooltip>
    <Tooltip.Trigger tag={Link} href='#'>
      Colored tooltip
    </Tooltip.Trigger>
    <Tooltip.Popper
      arrowBgColor={'bg-primary-advertising'}
      arrowShadowColor={'border-tooltip-invert'}
      p={0}
    >
      <Box
        style={{
          background: 'var(--intergalactic-bg-primary-advertising)',
          color: 'var(--intergalactic-text-primary-invert)',
          borderRadius: 'var(--intergalactic-popper-rounded)',
          borderColor: 'var(--intergalactic-border-tooltip-invert)',
        }}
        p={3}
      >
        Hey! I'm your colored tooltip!
      </Box>
    </Tooltip.Popper>
  </Tooltip>
);

export default Demo;
import React from 'react';
import Tooltip from 'intergalactic/tooltip';
import { Box } from 'intergalactic/flex-box';
import Link from 'intergalactic/link';

const Demo = () => (
  <Tooltip>
    <Tooltip.Trigger tag={Link} href='#'>
      Colored tooltip
    </Tooltip.Trigger>
    <Tooltip.Popper
      arrowBgColor={'bg-primary-advertising'}
      arrowShadowColor={'border-tooltip-invert'}
      p={0}
    >
      <Box
        style={{
          background: 'var(--intergalactic-bg-primary-advertising)',
          color: 'var(--intergalactic-text-primary-invert)',
          borderRadius: 'var(--intergalactic-popper-rounded)',
          borderColor: 'var(--intergalactic-border-tooltip-invert)',
        }}
        p={3}
      >
        Hey! I'm your colored tooltip!
      </Box>
    </Tooltip.Popper>
  </Tooltip>
);

export default Demo;

Released under the MIT License.

Released under the MIT License.