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. Refer to Tooltip API and Tooltip A11y for more details.
import React from 'react';
import Tooltip, { Hint, DescriptionTooltip } from '@semcore/tooltip';
import { Flex } from '@semcore/flex-box';
import { Text } from '@semcore/typography';
import Link from '@semcore/link';
import Button, { ButtonLink } from '@semcore/button';
import FileExportM from '@semcore/icon/FileExport/m';
import CheckAltM from '@semcore/icon/CheckAlt/m';
import InfoM from '@semcore/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={ButtonLink} use={'secondary'}>
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={ButtonLink}
addonLeft={InfoM}
color='icon-secondary-neutral'
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.
import React from 'react';
import Tooltip from '@semcore/tooltip';
import { Box, Flex } from '@semcore/flex-box';
import { ButtonLink } from '@semcore/button';
const Demo = () => (
<Flex>
<Box m='auto' p={5}>
<Tooltip>
<Tooltip.Trigger aria-describedby={undefined} role={undefined}>
{({ popperId }) => <ButtonLink aria-describedby={popperId}>Tooltip trigger</ButtonLink>}
</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.
import React from 'react';
import Tooltip from '@semcore/tooltip';
import Select from '@semcore/select';
import { Text } from '@semcore/typography';
import { Flex } from '@semcore/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: number) => void }) => {
const handleHighlightedIndexChange = React.useCallback(
(index: number | null) => {
if (index !== null) {
setTooltipIndex(index);
}
},
[setTooltipIndex],
);
return (
<Flex direction='column'>
<Text tag='label' size={200} htmlFor='select-with-tooltips'>
Select with tooltips
</Text>
<Select onHighlightedIndexChange={handleHighlightedIndexChange}>
<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}
// @ts-ignore
use:inline={false}
>
{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.
import React from 'react';
import Button from '@semcore/button';
import Modal from '@semcore/modal';
import { Text } from '@semcore/typography';
import { Box } from '@semcore/flex-box';
import Input from '@semcore/input';
import Tooltip from '@semcore/tooltip';
const Demo = () => {
const [visible, setVisible] = React.useState(false);
return (
<React.Fragment>
<Button onClick={() => setVisible(true)}>Open modal with tooltips</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-1' />
</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 background color
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.
import React from 'react';
import Tooltip from '@semcore/tooltip';
import { Box } from '@semcore/flex-box';
import { ButtonLink } from '@semcore/button';
const Demo = () => (
<Tooltip>
<Tooltip.Trigger tag={ButtonLink}>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;