Tooltip
A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
Quick Start
- Installation
npm install @adaptavant/eds-core- Import
import { Tooltip } from '@adaptavant/eds-core';
Default
Buttons can be wrapped in a tooltip to provide additional information about the button’s action.
The text for the tooltip can be provided via the content prop.
<Tooltip content="Copy">
{({ triggerProps }) => (
<IconButton
aria-label="Copy icon"
icon={ClipboardCopyIcon}
variant="neutralSecondary"
{...triggerProps}
/>
)}
</Tooltip>
Placement
Use the placement prop to change the position of the tooltip. The default is "top".
function TriggerWithPlacement({ placement }) {
return (
<Tooltip content="Tooltip content" placement={placement}>
{({ triggerProps }) => <Button {...triggerProps}>Placement: {placement}</Button>}
</Tooltip>
);
}
return (
<Stack className="items-stretch w-full gap-4">
<div className="grid grid-cols-3 gap-4">
<TriggerWithPlacement placement="top-start" />
<TriggerWithPlacement placement="top" />
<TriggerWithPlacement placement="top-end" />
</div>
<div className="grid grid-cols-3 gap-4">
<TriggerWithPlacement placement="left" />
<div />
<TriggerWithPlacement placement="right" />
</div>
<div className="grid grid-cols-3 gap-4">
<TriggerWithPlacement placement="bottom-start" />
<TriggerWithPlacement placement="bottom" />
<TriggerWithPlacement placement="bottom-end" />
</div>
</Stack>
);
Strategy
Use the strategy prop to change the CSS position property to use. This is used to pass the defined strategy to floating-ui library used in the Tooltip panel.
const [showFixedElement, setShowFixedElement] = React.useState(false);
const onButtonClick = () => {
setShowFixedElement((prevState) => !prevState)
}
return (
<Stack className="w-full gap-4">
{showFixedElement ? (
<div className="
animate-[snackbar-transition_0.3s_cubic-bezier(0.16,_1,_0.3,_1)]
bg-neutral-secondary
fixed
flex
items-center
justify-between
mx-2
p-4
right-0
rounded-8px
shadow-40
sm:right-8
sm:w-[360px]
top-8
w-[calc(100%-16px)]
z-10
">
<Tooltip content="Super important information" strategy="fixed">
{({ triggerProps }) => (
<Text href="#" {...triggerProps}>Super important...</Text>
)}
</Tooltip>
<button
className="focus-visible:focus-ring font-stronger px-1 py-0.5 rounded-4px shrink-0 text-body-12 underline underline-offset-2"
onClick={onButtonClick}
>Close</button>
</div>
) : null}
<Button onClick={onButtonClick}>
Show fixed element
</Button>
</Stack>
);
MaxWidth
To customize the tooltip's maximum width, you can use the maxWidth prop.
By default, the tooltip adjusts to the width of its content. However, a maxWidth is applied to ensure it's width doesn't exceed a certain limit. The default maxWidth is set to 200px.
<Tooltip content="Lorem Ipsum is simply dummy text of the printing and typesetting industry" maxWidth='300'>
{({ triggerProps }) => (
<IconButton
aria-label="Copy icon"
icon={ClipboardCopyIcon}
variant="neutralSecondary"
{...triggerProps}
/>
)}
</Tooltip>
Visibility
Use visibilityHidden prop to hide the tooltip. Probably, it can be used to hide tooltips for a disabled element.
<Tooltip content="Copy" visibilityHidden={true}>
{({ triggerProps }) => (
<IconButton
aria-label="Copy icon"
icon={ClipboardCopyIcon}
isDisabled={true}
variant="neutralSecondary"
{...triggerProps}
/>
)}
</Tooltip>
Adaptive Behaviour
Traditional tooltips rely on hover, which isn't supported on touch devices like mobile and tablet. This pattern automatically switches the tooltip experience on mobile and tablet to a tap-based dialog, making the content easier to read, interact with, and dismiss.
Use shouldAdaptToViewport prop to make tooltips adapt better on touch devices.
The Tooltip component already handles the responsive behavior and dialog state for you. You only need to connect the provided openDialog function to your trigger element.
⚠️ This feature is only available on mobile and tablet screens.
📱 View this example on mobile and tablet screens to actually see the dialog appearing instead of the regular tooltip.
<Box className="flex items-center gap-2">
<Toggle label="Feature toggle" />
<Tooltip
shouldAdaptToViewport={true}
content="On mobile and tablet screens, this tooltip opens as a dialog for better readability and accessibility."
>
{({ triggerProps, openDialog }) => (
<IconButton
aria-label="Copy icon"
icon={InformationIcon}
variant="neutralTertiary"
onClick={openDialog}
{...triggerProps}
/>
)}
</Tooltip>
</Box>
How it behaves across devices
With shouldAdaptToViewport enabled, the same Tooltip behaves differently depending on screen size:
- Desktop (1024px and above) Shows a standard hover tooltip.
- Tablet (768px - 1023px) Opens the tooltip as a Modal dialog.
- Mobile (below 768px) Opens the tooltip as a Sheet from the bottom.
This ensures tooltip content remains usable and accessible across all devices, without requiring separate implementations.
Interaction behavior
- Desktop: Hover to view tooltip
- Tablet: Tap to open dialog (Modal)
- Mobile: Tap to open dialog (Sheet)
Manual Close
Use the close callback from the render prop to programmatically dismiss the tooltip. This is useful when opening another overlay (like a dropdown menu) from the same trigger — the tooltip should immediately close so both don't appear simultaneously.
<DropdownMenu>
{({ triggerProps: menuTriggerProps, isMenuOpen }) => (
<>
<Tooltip content="More actions">
{({ triggerProps: tooltipTriggerProps, close }) => (
<IconButton
aria-label="More actions"
icon={MoreIcon}
variant="neutralSecondary"
{...mergeProps(tooltipTriggerProps, menuTriggerProps, {
onClick: () => (isMenuOpen ? close : null),
})}
/>
)}
</Tooltip>
<DropdownMenuPopover>
<DropdownMenuList
options={[
{ id: "option1", children: "Option 1", onClick: () => {} },
{ id: "option2", children: "Option 2", onClick: () => {} },
{ id: "option3", children: "Option 3", onClick: () => {} },
]}
>
{(option) => <DropdownMenuItem {...option} />}
</DropdownMenuList>
</DropdownMenuPopover>
</>
)}
</DropdownMenu>
close()only suppresses the current hover session — re-hovering the trigger will show the tooltip again normally.
With DropdownMenu
When using Tooltip alongside other layered components like DropdownMenu or Popover, it’s important to understand how their interactions work:
Default behavior:
- By default, the tooltip's visibility is independent of any associated popover or menu. This means that even if a popover (such as a dropdown) is open, hovering or focusing its trigger (e.g., an
IconButton) will still display the tooltip. - This design keeps Tooltip behavior consistent and predictable, leaving you in control of when or if the tooltip should be suppressed.
Controlling tooltip visibility:
- If your use case requires the tooltip to hide when another overlay (like a dropdown menu) connected to the same trigger is open, you can programmatically suppress the tooltip.
- To do so, use the
closecallback provided in the Tooltip's render prop. This allows you to immediately dismiss the tooltip when opening another overlay, ensuring only one is visible at a time and preventing UI overlap:
<DropdownMenu>
{({ triggerProps: menuTriggerProps, isMenuOpen }) => (
<>
<Tooltip content="More actions">
{({ triggerProps: tooltipTriggerProps, close }) => (
<IconButton
aria-label="More actions"
icon={MoreIcon}
variant="neutralSecondary"
{...mergeProps(tooltipTriggerProps, menuTriggerProps, {
onClick: () => (isMenuOpen ? close : null),
})}
/>
)}
</Tooltip>
<DropdownMenuPopover>
<DropdownMenuList
options={[
{ id: "option1", children: "Option 1", onClick: () => {} },
{ id: "option2", children: "Option 2", onClick: () => {} },
{ id: "option3", children: "Option 3", onClick: () => {} },
]}
>
{(option) => <DropdownMenuItem {...option} />}
</DropdownMenuList>
</DropdownMenuPopover>
</>
)}
</DropdownMenu>
This pattern is applicable to any layered components like
DropdownMenu,PopoverorModal.
API Reference
Tooltip
| Prop | Default | Description |
|---|---|---|
children | _ | (props: { triggerProps: TooltipTriggerProps<React.ElementType>, openDialog: () => void }) => React.ReactNodeThe child element that the tooltip will wrap, such as a button or other interactive element. |
content | _ | stringThe text or content that will be displayed inside the tooltip. |
id? | _ | stringAn optional ID for the tooltip. If no value is provided, an ID will be automatically generated |
maxWidth? | 200 | numberThe maximum width of the popover. |
placement? | top | 'top' | 'right' | 'bottom' | 'left' | 'top-start' | 'top-end' | 'right-start' | 'right-end' | 'bottom-start' | 'bottom-end' | 'left-start' | 'left-end'Internally imports type Placement from @floating-ui/react-dom Defines the tooltip's placement relative to the trigger element. |
shouldUsePortal? | true | booleanWhether the tooltip should be placed within a React Portal. |
strategy? | absolute | 'absolute' | 'fixed'Internally imports type Strategy from @floating-ui/react-dom The strategy used to position the floating element. |
visibilityHidden? | false | booleanControls the visibility of tooltip. When set to true tooltip will not render and removes all events in trigger element |
visibilityHiddenInMobile? | false | booleanControls the visibility of tooltip on mobile devices. When set to true tooltip will not render and removes all events in trigger element |
|
|
Dialog variants by viewport:
|
Style API
Our design system components include style props that allow you to easily customize different parts of each component to match your design needs.
Please refer to the Style API documentation for more insights.
Usage guidelines
Do
- Providing non-essential context: Use Tooltip to offer helpful, non-essential context to a UI element.
- Enhancing baseline understanding: Employ Tooltip to enhance the baseline understanding of an element or feature.
Don’t
- Critical information display: Do not use Tooltip for displaying information critical to the understanding of an element or feature. In such cases, use inline text instead.
Best practices
Do
Utilize Tooltip to succinctly describe the function of an interactive element, typically an IconButton, using as few words as possible.
Don’t
Avoid Tooltip to reiterate text that is already visible on the screen.
Do
Need to share a list? Use commas to keep it concise.
Don’t
Avoid using bulletpoints as this format isn’t possible from a code perspective.
Do
When truncating text, leave a hint to show there's more to read.
Don’t
Avoid removing all hints from the text to maintain context.