Tooltips display informative text when users hover over, focus on, or tap an element.
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>
</>
);
}
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>
</>
);
}
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>
</>
);
}
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>
</>
);
}
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>
</>
);
}
Since Tooltips are normally used with Buttons, 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>
</>
);
}
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>
);
}
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 to 1000leaveTimeout - The amount of time to wait in milliseconds before hiding the
tooltip. Defaults to 0disableTimeout (TooltipHoverModeProvider) - The amount of time to wait in
milliseconds before disabling the hover mode functionality. Defaults to 1000"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={10_000}
>
{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>
);
}
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>
);
}
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
refor changing thewidthso 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>
</>
);
}
A Tooltip can be rendered without the useTooltip hook but will require some
additional styling for the correct positioning to work.
disablePortal prop so it renders inlineposition: absolute positioningposition: relativetextOverflow prop to "nowrap" so that the width is not
restricted to the wrapper element's widthThis demo just showcases a possible use-case for the custom tooltip by rendering it with a progressbar to show the current progress.
Tooltips follow the tooltip pattern and the tooltip role.