Tooltip
Tooltips display informative text when users hover over, focus on, or tap an element.
Simple Example
A tooltip can be created by using the Tooltip
component and the useTooltip
hook to handle controlling the visibility. The default behavior will be to show
the tooltip after hovering/focusing/touching for 1 second.
"use client";
import { Button } from "@react-md/core/button/Button";
import { Tooltip } from "@react-md/core/tooltip/Tooltip";
import { useTooltip } from "@react-md/core/tooltip/useTooltip";
import { type ReactElement } from "react";
export default function SimpleTooltipExample(): ReactElement {
const { elementProps, tooltipProps } = useTooltip();
return (
<>
<Button {...elementProps}>Button</Button>
<Tooltip {...tooltipProps}>Tooltip</Tooltip>
</>
);
}
Dense Tooltip
The tooltip can be rendered with a smaller size and spacing from the tooltipped
element by enabling the dense
option.
"use client";
import { Button } from "@react-md/core/button/Button";
import { Tooltip } from "@react-md/core/tooltip/Tooltip";
import { useTooltip } from "@react-md/core/tooltip/useTooltip";
import { type ReactElement } from "react";
export default function DenseTooltipExample(): ReactElement {
const { elementProps, tooltipProps } = useTooltip({
dense: true,
});
return (
<>
<Button {...elementProps}>Button</Button>
<Tooltip {...tooltipProps}>Tooltip</Tooltip>
</>
);
}
Long Text Tooltip
Tooltips have a max-width
set to 15rem
by default but can be configured by
setting the core.$tooltip-max-width Sass variable or through CSS on the
tooltip.
"use client";
import { Button } from "@react-md/core/button/Button";
import { Tooltip } from "@react-md/core/tooltip/Tooltip";
import { useTooltip } from "@react-md/core/tooltip/useTooltip";
import { type ReactElement } from "react";
export default function LongTextTooltipExample(): ReactElement {
const { elementProps, tooltipProps } = useTooltip();
return (
<>
<Button {...elementProps}>Button</Button>
<Tooltip {...tooltipProps}>
Nam laoreet, felis ut commodo tristique, dui lorem iaculis metus, vitae
pharetra ipsum nulla sed mauris. Suspendisse ultrices vel dui id
posuere. Aenean pellentesque urna ac nisi elementum fringilla. Sed quis
vestibulum ex, in auctor lorem. Morbi a elit viverra, dignissim leo at,
accumsan ligula. Aliquam velit ligula, molestie a lorem ut, commodo
hendrerit est. Sed lobortis luctus orci quis ultricies. Nullam luctus
urna quis libero aliquet, non tincidunt augue sagittis. Duis eleifend
ultricies fermentum. Nulla volutpat tempor est, eget hendrerit nisi
sodales vitae.
</Tooltip>
</>
);
}
Tooltip Positioning
The Tooltip
will automatically attempt to render itself within the viewport
either above or below the tooltipped element preferring below. The positioning
can be configured by providing the defaultPosition
option to the useTooltip
hook as one of the following:
"below"
(default) - renders the tooltip below the tooltipped element and swaps to above if near the bottom of the viewport"above"
- renders the tooltip above the tooltipped element and swaps to below if near the top of the viewport"left"
- renders the tooltip to the left of the tooltipped element and swaps to the right if near the left edge of the viewport"right"
- renders the tooltip to the right of the tooltipped element and swaps to the left if near the right edge of the viewport
"use client";
import { Button } from "@react-md/core/button/Button";
import { Tooltip } from "@react-md/core/tooltip/Tooltip";
import { useTooltip } from "@react-md/core/tooltip/useTooltip";
import { type ReactElement } from "react";
export default function TooltipPositioningExample(): ReactElement {
const { elementProps, tooltipProps } = useTooltip({
// this is the default
defaultPosition: "below",
// defaultPosition: "above",
// defaultPosition: "left",
// defaultPosition: "right",
});
return (
<>
<Button {...elementProps}>Button</Button>
<Tooltip {...tooltipProps}>Tooltip</Tooltip>
</>
);
}
Forced Tooltip Position
A specific position can be forced by setting the position
option instead.
"use client";
import { Button } from "@react-md/core/button/Button";
import { Tooltip } from "@react-md/core/tooltip/Tooltip";
import { useTooltip } from "@react-md/core/tooltip/useTooltip";
import { type ReactElement } from "react";
export default function ForcedTooltipPositionExample(): ReactElement {
const { elementProps, tooltipProps } = useTooltip({
// this is the default
position: "below",
// position: "above",
// position: "left",
// position: "right",
});
return (
<>
<Button {...elementProps}>Button</Button>
<Tooltip {...tooltipProps}>Tooltip</Tooltip>
</>
);
}
Tooltipped Button
Since Tooltip
s are normally used with Button
s, a simple helper component is
available to automatically render a tooltip when a tooltip
prop is provided. The
TooltippedButton
also defaults the buttonType
to "icon"
instead of "text"
like normal buttons.
import { TooltippedButton } from "@react-md/core/button/TooltippedButton";
import CloseIcon from "@react-md/material-icons/CloseIcon";
import FavoriteIcon from "@react-md/material-icons/FavoriteIcon";
import { type ReactElement } from "react";
export default function TooltippedButtonExample(): ReactElement {
return (
<>
<TooltippedButton aria-label="No tooltip">
<CloseIcon />
</TooltippedButton>
<TooltippedButton
aria-label="Favorite"
tooltip="Tooltip"
themeType="outline"
>
<FavoriteIcon />
</TooltippedButton>
<TooltippedButton
aria-label="Favorite"
tooltip={
<span>
<strong>Strong</strong> tooltip
</span>
}
theme="success"
>
<FavoriteIcon />
</TooltippedButton>
</>
);
}
Enabling Hover Mode
Tooltips can also be updated to have a "hover mode" so that subsequent tooltips
are shown immediately instead of requiring the default delay. After no tooltips
have been shown via mouse for a few seconds, the "hover mode" will be disabled
and the initial hover delay will be used again. This feature can be enabled for
all tooltips in the application or just a small group of tooltips by wrapping
the components in the TooltipHoverModeProvider
.
"use client";
import { TooltippedButton } from "@react-md/core/button/TooltippedButton";
import { TooltipHoverModeProvider } from "@react-md/core/tooltip/TooltipHoverModeProvider";
import { type ReactElement } from "react";
export default function EnablingHoverModeExample(): ReactElement {
return (
<TooltipHoverModeProvider>
{Array.from({ length: 5 }, (_, i) => (
<TooltippedButton
key={i}
tooltip={`Tooltip ${i + 1}`}
buttonType="text"
>
Button {i + 1}
</TooltippedButton>
))}
</TooltipHoverModeProvider>
);
}
Configuring Tooltip Timeouts
The timeouts for showing and hiding the tooltips can be configured globally
using the TooltipHoverModeProvider
or a tooltip-by-tooltip basis with the
useTooltip
hook which would override the TooltipHoverModeProvider
value.
hoverTimeout
- The amount of time to wait in milliseconds before showing the tooltip. Defaults to1000
leaveTimeout
- The amount of time to wait in milliseconds before hiding the tooltip. Defaults to0
disableTimeout
(TooltipHoverModeProvider
) - The amount of time to wait in milliseconds before disabling the hover mode functionality. Defaults to1000
"use client";
import { TooltippedButton } from "@react-md/core/button/TooltippedButton";
import { TooltipHoverModeProvider } from "@react-md/core/tooltip/TooltipHoverModeProvider";
import { type ReactElement } from "react";
export default function ConfiguringTooltipTimeoutsExample(): ReactElement {
return (
<TooltipHoverModeProvider
hoverTimeout={500}
leaveTimeout={300}
disableTimeout={10000}
>
{Array.from({ length: 5 }, (_, i) => (
<TooltippedButton
key={i}
tooltip={`Tooltip ${i + 1}`}
buttonType="text"
>
{`Button ${i + 1}`}
</TooltippedButton>
))}
<TooltippedButton
tooltip="Another tooltip"
// these are pass-through to the `useTooltip` hook
// i.e.
// useTooltip({ ...tooltipOptions, disabled: !tooltip || tooltipOptions?.disabled })
tooltipOptions={{
leaveTimeout: 1000,
hoverTimeout: 1500,
}}
buttonType="text"
>
Custom Timeout
</TooltippedButton>
</TooltipHoverModeProvider>
);
}
Overflow Only Tooltip
The useTooltip
hook also supports an overflowOnly
option that will display
the tooltip only while there is overflown content for the tooltipped element.
"use client";
import { Box } from "@react-md/core/box/Box";
import { cssUtils } from "@react-md/core/cssUtils";
import { Tooltip } from "@react-md/core/tooltip/Tooltip";
import { useTooltip } from "@react-md/core/tooltip/useTooltip";
import { type CSSProperties, type ReactElement } from "react";
const style: CSSProperties = {
width: "8rem",
};
export default function OverflowOnlyTooltipExample(): ReactElement {
const { elementProps, tooltipProps } = useTooltip<HTMLDivElement>({
overflowOnly: true,
});
return (
<Box stacked>
<div
{...elementProps}
style={style}
className={cssUtils({ textOverflow: "ellipsis" })}
>
No Overflow.
</div>
<div
{...elementProps}
style={style}
className={cssUtils({ textOverflow: "ellipsis" })}
>
There will be overflow here.
</div>
<Tooltip {...tooltipProps}>Tooltip!</Tooltip>
</Box>
);
}
Custom Overflow Element
If the tooltipped element is a flex or grid container, a child element will most
likely need to be updated to add the overflow styles. This would cause the
tooltip to never appear since the tooltipped element is not considered overflown
even though the child is truncated. In this case, add the overflowRef
to the
truncated element and the tooltip will correctly appear.
Try commenting out the
ref
or changing thewidth
so there is no truncated text in this example and hover the button.
"use client";
import { Button } from "@react-md/core/button/Button";
import { cssUtils } from "@react-md/core/cssUtils";
import { Tooltip } from "@react-md/core/tooltip/Tooltip";
import { useTooltip } from "@react-md/core/tooltip/useTooltip";
import { type ReactElement } from "react";
export default function CustomOverflowElementExample(): ReactElement {
const { elementProps, tooltipProps, overflowRef } = useTooltip({
overflowOnly: true,
});
return (
<>
<Button {...elementProps} style={{ width: "2rem" }}>
<span
ref={overflowRef}
className={cssUtils({ textOverflow: "ellipsis" })}
>
Some long content
</span>
</Button>
<Tooltip {...tooltipProps}>Tooltip!</Tooltip>
</>
);
}
Custom Tooltip
A Tooltip
can be rendered without the useTooltip
hook but will require some
additional styling for the correct positioning to work.
- Enable the
disablePortal
prop so it renders inline - Add styles for
position: absolute
positioning - Wrap in a container element with
position: relative
- Optionally set the
textOverflow
prop to"nowrap"
so that the width is not restricted to the wrapper element's width
Progressbar Tooltip Example
This demo just showcases a possible use-case for the custom tooltip by rendering it with a progressbar to show the current progress.
Accessibility
Tooltips follow the tooltip pattern and the tooltip role.