JGuang

Tooltip

Tooltip · Mantine Core

Preview
npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1

Tooltip

Install: npm install @mantine/core@9.7.1 @mantine/hooks@9.7.1

Version and compatibility

Pinned Mantine Core 9.7.1 requires React and React DOM ^19.2.0 and matching @mantine/hooks@9.7.1, from the installed npm package's peerDependencies. Do not force it into React 18 or another incompatible version. Explain upgrade impact and agree on a plan with the project owner; do not hide conflicts with --force/--legacy-peer-deps. The native Provider enables theme.respectReducedMotion and uses forceColorScheme for light/dark.

Use case

Provide a short hint on hover or focus.

Native props used by this example

These props are extracted from the local typechecked JSX and grouped by their owning native component. This is not an exhaustive prop list; see pinned source signatures and inheritance below.

Component propExplanation
Tooltip.labelVisible label or component-specific label content.

Interaction and state checks

Current scenarios: Default. Check actual behavior after selecting supported disabled/error/read-only scenarios; components without those native states do not receive invented universal props. Verify keyboard focus and exits, then connect changed values through the native callback signature.

Business integration boundary

Demo content/state is local, without server persistence, authorization or fetching. A static display component is not a completed business workflow.

Host setup

Install pinned @mantine/core and @mantine/hooks, import @mantine/core/styles.css at the entry and use MantineProvider. The example's theme/variant are JGuang-authored host props, not universal native component APIs; forceColorScheme synchronizes the app theme. Native implementation source is a reading reference: use npm exports rather than copying internal engines. This batch covers Core, not dates/charts/forms extension packages. Detailed upstream prose remains English.

Runnable usage

import { useState } from 'react';
import * as M from '@mantine/core';
import '@mantine/core/styles.css';


function ComponentPreview({ variant = 'Default' }: { variant?: string }) {

return <M.Tooltip label="A helpful hint"><M.Button>Hover or focus</M.Button></M.Tooltip>;
}
export default function Example({ variant = 'Default', theme = 'light' }: { variant?: string; theme?: 'light' | 'dark' }) {
return <M.MantineProvider forceColorScheme={theme} theme={{ respectReducedMotion: true }}><ComponentPreview variant={variant} /></M.MantineProvider>;
}

Preview states

Default

The example uses the native Mantine API. For supported input demos, change the local variant to Disabled, Invalid or Read only; these are example labels, not new component props. Keep the documented data, controlled values, stores and compound children when adapting the example.

Usage

Tooltip children

Tooltip requires an element or a component as a single child – strings, fragments, numbers and multiple elements/components are not supported and will throw an error. Custom components must provide a prop to get the root element ref; all Mantine components support ref out of the box.

import { Badge, Tooltip } from '@mantine/core';

function Demo() {
  return (
    <>
      <Tooltip label="OK">
        <button>Native button – ok</button>
      </Tooltip>

      <Tooltip label="OK">
        <Badge>Mantine component – ok</Badge>
      </Tooltip>

      <Tooltip label="Throws">
        Raw string, NOT OK – will throw an error
      </Tooltip>

      {/* Number, NOT OK – will throw an error */}
      <Tooltip label="Throws">{2}</Tooltip>

      <Tooltip label="Throws">
        <>Fragment, NOT OK, will throw an error</>
      </Tooltip>

      <Tooltip label="Throws">
        <div>More than one node</div>
        <div>NOT OK, will throw an error</div>
      </Tooltip>
    </>
  );
}

Tooltip target

The target prop is an alternative to children. It accepts a string (selector), an HTML element or a ref object with an HTML element. Use the target prop when you do not render the tooltip target as a JSX element.

Example of using the target prop with a string selector:

Hide detached

Use the hideDetached prop to configure how the tooltip behaves when the target element is removed from the DOM, hidden with display: none, or scrolled out of the viewport or of a scrollable container that clips it.

By default, hideDetached is enabled – the tooltip is hidden with the target element. You can change this behavior with hideDetached={false}.

Note that hideDetached has no effect on Tooltip.Floating – it is positioned relative to the mouse pointer rather than to a target element.

In test environments based on jsdom (Jest, Vitest) every element reports a zero-size rectangle, so the target is always considered detached and the tooltip is hidden. Set env="test" on MantineProvider in your test wrapper, as described in the Jest and Vitest guides, or pass hideDetached={false} – otherwise hideDetached detection is disabled only in the test environment.

To see the difference, try to scroll the root element of the following demo:

Required ref prop

Custom components that are rendered inside Tooltip are required to support ref prop:

// Example of code that WILL NOT WORK
import { Tooltip } from '@mantine/core';

function MyComponent() {
  return <div>My component</div>;
}

// This will not work – MyComponent does not support ref
function Demo() {
  return (
    <Tooltip label="Does not work">
      <MyComponent />
    </Tooltip>
  );
}

The component must support ref prop:

// Example of code that will work
import { Tooltip } from '@mantine/core';

const MyComponent = ({ ref, ...props }) => (
  <div ref={ref} {...props}>
    My component
  </div>
);

// Works correctly – ref is forwarded
function Demo() {
  return (
    <Tooltip label="Works fine">
      <MyComponent />
    </Tooltip>
  );
}

Color

Offset

Set the offset prop to a number to change the tooltip position relative to the target element. This way you can control the tooltip offset on the main axis only.

To control the offset on both axes, pass an object with mainAxis and crossAxis properties:

Arrow

Set the withArrow prop to add an arrow to the tooltip. The arrow is a div element rotated with transform: rotate(45deg).

The arrowPosition prop determines how the arrow is positioned relative to the target element when position is set to *-start and *-end values on the Popover component. By default, the value is center – the arrow is positioned in the center of the target element if it is possible.

If you change arrowPosition to side, then the arrow will be positioned on the side of the target element, and you will be able to control the arrow offset with the arrowOffset prop. Note that when arrowPosition is set to center, the arrowOffset prop is ignored.

If you set arrowPosition to merge, the arrow will form a right triangle merged with the corresponding corner of the tooltip, and the border radius of that corner will be removed. This mode only works with *-start and *-end positions. Note that arrowOffset and arrowRadius props are ignored when arrowPosition is set to merge.

Controlled

Change events

Events that trigger the tooltip can be changed with the events prop; it accepts an object with the following properties that determine which events will trigger the tooltip:

  • hover – mouse hover event, true by default
  • focus – focus/blur events excluding clicks on the target element, false by default
  • touch – events for touchscreen devices, false by default
import { Tooltip } from '@mantine/core';

function Demo() {
  return (
    <Tooltip
      label="Tooltip"
      events={{ hover: true, focus: true, touch: false }}
    >
      <button>target</button>
    </Tooltip>
  );
}

Interactive tooltip

By default, the tooltip closes as soon as the pointer leaves the target element, and the tooltip body ignores pointer events. Set the interactive prop to keep the tooltip open while the pointer travels from the target to the tooltip and rests over its content.

The interactive prop satisfies the hoverable condition of WCAG 2.1 success criterion 1.4.13: Content on Hover or Focus, so the pointer can reach the tooltip body without dismissing it, for example to read or select its content.

Do not put interactive or focusable content (links, buttons, inputs) inside a tooltip. Interactive content should be put in a Popover instead, which is reachable by mouse, keyboard, and touch.

Note that an interactive tooltip receives pointer events, which means that while it is open, it intercepts clicks and hover events of the elements that it overlaps. The tooltip stops receiving pointer events as soon as it starts closing. The interactive prop is not supported by Tooltip.Floating, which always follows the mouse.

Multiline

To enable multiline mode, set the multiline prop to enable line breaks and the w style prop to set the tooltip width:

Inline

Set the inline prop to use Tooltip with inline elements:

Change transition

Tooltip is built with the Transition component; it supports transitionProps props:

import { Button, Tooltip } from '@mantine/core';

function Demo() {
  return (
    <Tooltip
      label="Tooltip with custom transition"
      transitionProps={{ transition: 'skew-up', duration: 300 }}
    >
      <Button>Button with tooltip</Button>
    </Tooltip>
  );
}

All available premade transitions:

Close and open delay

You can delay tooltip open/close events by setting the openDelay and closeDelay props in ms:

Tooltip delay group

The Tooltip.Group component can be used to sync open and close delays for multiple tooltips:

Floating tooltip

Tooltip.Floating component has the same API as the Tooltip component but the tooltip will follow the mouse:

Accessibility

Tooltip follows the WAI-ARIA tooltip pattern:

  • The tooltip body has role="tooltip" attribute
  • The target element has aria-describedby attribute
  • Tooltip.Floating is ignored by screen readers
  • Uncontrolled tooltips are dismissed with Escape without moving the pointer or focus

By default, Tooltip is not triggered by focus events and thus users who use a screen reader or navigate with the keyboard will not be able to get tooltip content. Set the events prop to enable focus/blur tooltip events:

import { Button, Tooltip } from '@mantine/core';

// Tooltip will be visible for screen readers
function Demo() {
  return (
    <Tooltip
      label="Tooltip"
      events={{ hover: true, focus: true, touch: false }}
    >
      <Button>Button with tooltip</Button>
    </Tooltip>
  );
}

WCAG 2.1 success criterion 1.4.13: Content on Hover or Focus additionally requires content that appears on hover to be dismissable, hoverable and persistent. Tooltip is persistent out of the box and dismissable if its opened state is not controlled (Escape closes it without moving the pointer – if you control the opened prop, you are responsible for handling Escape yourself). Tooltip is not hoverable by default – set the interactive prop to make the tooltip body hoverable:

import { Button, Tooltip } from '@mantine/core';

// Tooltip stays open while the pointer is over its content
function Demo() {
  return (
    <Tooltip label="Tooltip" interactive>
      <Button>Button with tooltip</Button>
    </Tooltip>
  );
}

Source-backed parameter reference

Implementation signatures and types are generated from the pinned local source. Optional props, native inherited types, union branches and never exclusions are preserved. A forwardRef implementation's ref is a React reference, not an additional business prop.

Tooltip(_props)
export interface TooltipProps extends TooltipBaseProps {
  /** Called when tooltip position changes */
  onPositionChange?: (position: FloatingPosition) => void;

  /** Open delay in ms */
  openDelay?: number;

  /** Close delay in ms @default 0 */
  closeDelay?: number;

  /** Controlled opened state */
  opened?: boolean;

  /** Uncontrolled tooltip initial opened state */
  defaultOpened?: boolean;

  /** Space between target element and tooltip in px @default 5 */
  offset?: number | FloatingAxesOffsets;

  /** If set, the tooltip has an arrow @default false */
  withArrow?: boolean;

  /** Arrow size in px @default 4 */
  arrowSize?: number;

  /** Arrow offset in px @default 5 */
  arrowOffset?: number;

  /** Arrow `border-radius` in px @default 0 */
  arrowRadius?: number;

  /** Arrow position relative to the tooltip @default side */
  arrowPosition?: ArrowPosition;

  /** Props passed down to the `Transition` component that used to animate tooltip presence, use to configure duration and animation type @default { duration: 100, transition: 'fade' } */
  transitionProps?: TransitionOverride;

  /** Determines which events will be used to show tooltip @default { hover: true, focus: false, touch: false } */
  events?: { hover: boolean; focus: boolean; touch: boolean };

  /** If set, the tooltip stays open while the pointer is over it @default false */
  interactive?: boolean;

  /** Must be set if the tooltip target is an inline element */
  inline?: boolean;

  /** If set, the tooltip is not unmounted from the DOM when hidden, `display: none` styles are applied instead */
  keepMounted?: boolean;

  /** Changes floating ui [position strategy](https://floating-ui.com/docs/usefloating#strategy) @default 'absolute' */
  floatingStrategy?: FloatingStrategy;

  /** If set, adjusts text color based on background color for `filled` variant */
  autoContrast?: boolean;

  /** Selector, ref of an element or element itself that should be used for positioning */
  target?: React.RefObject<HTMLElement | null> | HTMLElement | null | string;

  /** If set, the tooltip is hidden when the target element is removed from the DOM, hidden with `display: none` or scrolled out of the visible area. Has no effect on `Tooltip.Floating` @default true */
  hideDetached?: boolean;
}

export type TooltipFactory = Factory<{
  props: TooltipProps;
  ref: HTMLDivElement;
  stylesNames: TooltipStylesNames;
  vars: TooltipCssVariables;
  staticComponents: {
    Floating: typeof TooltipFloating;
    Group: typeof TooltipGroup;
  };
}>;

Native and external types

External types remain defined by React or native dependencies, not manually expanded into guessed props. The installed version's TypeScript definitions are authoritative.

Factory<{
  props: TooltipProps;
  ref: HTMLDivElement;
  stylesNames: TooltipStylesNames;
  vars: TooltipCssVariables;
  staticComponents: {
    Floating: typeof TooltipFloating;
    Group: typeof TooltipGroup;
  };
}>
TooltipBaseProps
FloatingPosition
FloatingAxesOffsets
ArrowPosition
TransitionOverride
FloatingStrategy
React.RefObject<HTMLElement | null>
HTMLElement
HTMLDivElement
TooltipStylesNames
TooltipCssVariables