# Tooltip

A tooltip provides supplemental, contextual information elevated near its target component. Tooltips should be used to provide helpful but non-essential, plaintext information.

## Best practices

### Do

- Use tooltips for helpful, non-essential, plaintext information.
- Provide additional information rather than repeating visible content.
- Position the tooltip so it does not obscure important information.

### Don't

- Use tooltips to communicate system feedback.
- Add end punctuation unless the tooltip contains a complete sentence.

## Behavior and states

- Tooltips open when the target receives hover or focus.
- They close on blur or when the pointer leaves the target or tooltip container.
- Tooltips appear 4 pixels from their target by default.
- The optional arrow always points to the target element.
- Don't use them to communicate system feedback.
- If you need to deliver robust, formatted information, use a popover instead.

## Default

Source: CoreAI.

[Download source](/coreai-design-system/source/examples/components-tooltip--default.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { TooltipProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { SlideTextRegular } from "@fluentui/react-icons";
import * as React from 'react';

export const Default = (props: Partial<TooltipProps>): JSXElement => (<Tooltip content="Example tooltip" relationship="label" {...props}>
    <Button icon={<SlideTextRegular />} size="large"/>
  </Tooltip>);

export default Default;
```

## API

Generated CoreAI prop summaries, not replacement type declarations. Most native DOM/event and ARIA props are omitted. `?` means optional; JSDoc shows defaults, deprecations, and conditional requirements. Defaults assume the standard CoreAI provider.

### Tooltip API

A tooltip provides light weight contextual information on top of its target element.

```ts
interface TooltipProps {
  /**
   * The tooltip's visual appearance.
   * * `normal` - Uses the theme's background and text colors.
   * * `inverted` - Higher contrast variant that uses the theme's inverted colors.
   * @default normal
   */
  appearance?: "inverted" | "normal";

  children?: ReactElement<any, string | JSXElementConstructor<any>> | ((props: TooltipTriggerProps) => ReactElement<any, string | JSXElementConstructor<any>> | null) | null;

  /**
   * The text or JSX content of the tooltip.
   */
  content: NonNullable<WithSlotShorthandValue<{ as?: "div" | undefined; } & Omit<Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & { ref?: ((instance: HTMLDivElement | null) => void) | RefObject<HTMLDivElement> | null | undefined; }, "children"> & { children?: any; }> | null>;

  /**
   * Delay before the tooltip is hidden, in milliseconds.
   * @default 250
   */
  hideDelay?: number;

  /**
   * Where the portal children are mounted on DOM
   * @default a new element on document.body without any styling
   */
  mountNode?: HTMLElement | { element?: HTMLElement | null; className?: string; } | null | undefined;

  /**
   * Notification when the visibility of the tooltip is changing.
   *
   * **Note**: for backwards compatibility, `event` will be undefined if this was triggered by a keyboard event on
   * the document element. Use `data.documentKeyboardEvent` if the keyboard event object is needed.
   */
  onVisibleChange?: ((event: PointerEvent<HTMLElement> | FocusEvent<HTMLElement, Element>, data: OnVisibleChangeData) => void);

  /**
   * Configure the positioning of the tooltip
   * @default above
   */
  positioning?: PositioningShorthand;

  /**
   * (Required) Specifies whether this tooltip is acting as the description or label of its trigger element.
   *
   * * `label` - The tooltip sets the trigger's aria-label or aria-labelledby attribute. This is useful for buttons
   *    displaying only an icon, for example.
   * * `description` - The tooltip sets the trigger's aria-description or aria-describedby attribute.
   * * `inaccessible` - No aria attributes are set on the trigger. This makes the tooltip's content inaccessible to
   *   screen readers, and should only be used if the tooltip's text is available by some other means.
   */
  relationship: "label" | "description" | "inaccessible";

  /**
   * Delay before the tooltip is shown, in milliseconds.
   * @default 250
   */
  showDelay?: number;

  /**
   * Control the tooltip's visibility programatically.
   *
   * This can be used in conjunction with onVisibleChange to modify the tooltip's show and hide behavior.
   *
   * If not provided, the visibility will be controlled by the tooltip itself, based on hover and focus events on the
   * trigger (child) element.
   * @default false
   */
  visible?: boolean;

  /**
   * Render an arrow pointing to the target element
   * @default false
   */
  withArrow?: boolean;
}
```

## Implementation

CoreAI 0.12.0; Fluent 9.74.9.

[Setup and dependencies](/coreai-design-system/guides/Package.md).

Import components from `@coreai-ds/react-components`. CoreAI guidance above takes precedence over API demonstration examples.

Note: Storybook-only layout decorators are omitted. Examples use the documentation preview spacing instead.

## Controlled

Source: Fluent, adapted for CoreAI.

The visibility of the tooltip can be controlled using the `visible` and `onVisibleChange` props.
        <br />
        In this example, the tooltip will show on hover or focus _only if_ the checkbox is checked.

[Download source](/coreai-design-system/source/examples/components-tooltip--controlled.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { Tooltip } from "@coreai-ds/react-components";
import { Checkbox } from "@coreai-ds/react-components";

export const Controlled = (): JSXElement => {
    const [visible, setVisible] = React.useState(false);
    const [enabled, setEnabled] = React.useState(false);
    return (<Tooltip content="The checkbox controls whether the tooltip can show on hover or focus" relationship="description" visible={visible && enabled} onVisibleChange={(_ev, data) => setVisible(data.visible)}>
      <Checkbox label="Enable the tooltip" onChange={(_ev, { checked }) => setEnabled(!!checked)}/>
    </Tooltip>);
};

export default Controlled;
```

## Custom Mount

Source: Fluent, adapted for CoreAI.

Tooltips are rendered in a React Portal. By default that Portal is the outermost div.
      A custom `mountNode` can be provided in the case that the tooltip needs to be rendered elsewhere.

[Download source](/coreai-design-system/source/examples/components-tooltip--custom-mount.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { TooltipProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { SlideTextRegular } from "@fluentui/react-icons";

export const CustomMount = (props: Partial<TooltipProps>): JSXElement => {
    const [ref, setRef] = React.useState<HTMLElement | null>();
    return (<>
      <Tooltip mountNode={ref} content="Example tooltip" relationship="label" {...props}>
        <Button icon={<SlideTextRegular />} size="large"/>
      </Tooltip>
      <div ref={setRef}/>
    </>);
};

export default CustomMount;
```

## Icon

Source: Fluent, adapted for CoreAI.

When tooltips are attached to icons, they should use the InfoLabel control to be accessible. Tooltips should not be attached directly to static elements like icons, and nor should static elements be given a tabindex.

[Download source](/coreai-design-system/source/examples/components-tooltip--icon.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { InfoLabelProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { InfoLabel } from "@coreai-ds/react-components";
import { Link } from "@coreai-ds/react-components";
import * as React from 'react';

export const Icon = (props: Partial<InfoLabelProps>): JSXElement => {
    return (<InfoLabel info={<>
          This is example information for an InfoLabel. <Link href="https://react.fluentui.dev">Learn more</Link>
        </>} {...props}>
      This is an icon with an InfoLabel to show extra information
    </InfoLabel>);
};

export default Icon;
```

## Appearance: inverted

Source: Fluent, adapted for CoreAI.

The `appearance` prop can be set to `inverted` to use the theme's inverted colors.

[Download source](/coreai-design-system/source/examples/components-tooltip--inverted.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { SlideTextFilled } from "@fluentui/react-icons";
import * as React from 'react';

export const Inverted = (): JSXElement => (<Tooltip appearance="inverted" content="Example inverted tooltip" relationship="label">
    <Button icon={<SlideTextFilled />} size="large"/>
  </Tooltip>);

export default Inverted;
```

## Overflow Hidden

Source: Fluent, adapted for CoreAI.

When a tooltip trigger scrolls out of an overflow container, the tooltip should hide instead of rendering outside the clipped boundary.

[Download source](/coreai-design-system/source/examples/components-tooltip--overflow-hidden.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

const useStyles = makeStyles({
    root: {
        display: 'flex',
        flexDirection: 'column',
        gap: tokens.spacingVerticalS,
        alignItems: 'flex-start',
    },
    description: {
        margin: 0,
        fontSize: tokens.fontSizeBase300,
    },
    scrollContainer: {
        height: '120px',
        width: '240px',
        overflow: 'hidden scroll',
        border: `${tokens.strokeWidthThin} solid ${tokens.colorNeutralStroke1}`,
        borderRadius: tokens.borderRadiusMedium,
        position: 'relative',
    },
    content: {
        height: '300px',
        paddingTop: tokens.spacingVerticalS,
        paddingLeft: tokens.spacingHorizontalS,
    },
});

export const OverflowHidden = (): JSXElement => {
    const styles = useStyles();
    return (<div className={styles.root}>
      <p className={styles.description}>
        Scroll the box below. The tooltip should disappear when the button scrolls out of view, not follow it outside
        the container boundary.
      </p>
      <div className={styles.scrollContainer}>
        <div className={styles.content}>
          <Tooltip content="I should hide when scrolled out of view" relationship="label">
            <Button>Hover me, then scroll</Button>
          </Tooltip>
        </div>
      </div>
    </div>);
};

export default OverflowHidden;
```

## Positioning

Source: Fluent, adapted for CoreAI.

The positioning attribute can be used to change the relative placement of the tooltip to its anchor.
        <br />
        Hover or focus the buttons in the example to see the tooltip's placement.

[Download source](/coreai-design-system/source/examples/components-tooltip--positioning.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { ArrowStepOverRegular } from "@fluentui/react-icons";
import { ArrowStepOutRegular } from "@fluentui/react-icons";
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const Positioning = (): JSXElement => {
    /* eslint-disable react/jsx-key */
    const positions = [
        ['above-start', <ArrowStepOverRegular transform="rotate(-90)"/>],
        ['above', <ArrowStepOutRegular />],
        ['above-end', <ArrowStepOverRegular transform="rotate(90) scale(-1 1)"/>],
        ['before-top', <ArrowStepOverRegular transform="scale(-1 1)"/>],
        ['before', <ArrowStepOutRegular transform="rotate(-90)"/>],
        ['before-bottom', <ArrowStepOverRegular transform="rotate(180)"/>],
        ['after-top', <ArrowStepOverRegular />],
        ['after', <ArrowStepOutRegular transform="rotate(90)"/>],
        ['after-bottom', <ArrowStepOverRegular transform="rotate(180) scale(-1 1)"/>],
        ['below-start', <ArrowStepOverRegular transform="rotate(-90) scale(-1 1)"/>],
        ['below', <ArrowStepOutRegular transform="rotate(180)"/>],
        ['below-end', <ArrowStepOverRegular transform="rotate(90)"/>],
    ] as const;
    return (<div style={{
            display: 'grid',
            margin: '24px 128px',
            gap: '4px',
            gridTemplateAreas: '".             above-start   above         above-end     .            "' +
                '"before-top    .             .             .             after-top    "' +
                '"before        .             .             .             after        "' +
                '"before-bottom .             .             .             after-bottom "' +
                '".             below-start   below         below-end     .            "',
        }}>
      {positions.map(([position, icon]) => (<Tooltip key={position} withArrow positioning={position} content={position} relationship="label">
          <Button icon={icon} size="large" style={{ gridArea: position, minWidth: '64px', height: '64px' }}/>
        </Tooltip>))}
    </div>);
};

export default Positioning;
```

## Relationship: description

Source: Fluent, adapted for CoreAI.

A tooltip can be used as the description of its trigger. For example, this is used for controls that have
        a visible label, but the tooltip provides additional descriptive information.
        <br />
        The tooltip sets itself as the trigger's `aria-describedby`, so the tooltip is accessible to screen readers
        and other assistive technology.

[Download source](/coreai-design-system/source/examples/components-tooltip--relationship-description.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import * as React from 'react';

export const RelationshipDescription = (): JSXElement => (<Tooltip content="This is the description of the button" relationship="description">
    <Button>Button</Button>
  </Tooltip>);

export default RelationshipDescription;
```

## Relationship: label

Source: Fluent, adapted for CoreAI.

A tooltip can be used as the label of its trigger. For example, a label tooltip can be used for buttons
        that have only an icon and no visible label text.
        <br />
        The tooltip sets its `content` as the trigger's `aria-label`, so the tooltip is accessible to screen
        readers and other assistive technology.

[Download source](/coreai-design-system/source/examples/components-tooltip--relationship-label.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { TextBoldRegular } from "@fluentui/react-icons";
import { TextItalicRegular } from "@fluentui/react-icons";
import { TextUnderlineRegular } from "@fluentui/react-icons";
import * as React from 'react';

export const RelationshipLabel = (): JSXElement => (<>
    <Tooltip content="Bold" relationship="label">
      <Button icon={<TextBoldRegular />}/>
    </Tooltip>
    <Tooltip content="Italic" relationship="label">
      <Button icon={<TextItalicRegular />}/>
    </Tooltip>
    <Tooltip content="Underline" relationship="label">
      <Button icon={<TextUnderlineRegular />}/>
    </Tooltip>
  </>);

export default RelationshipLabel;
```

## Styled

Source: Fluent, adapted for CoreAI.

To style a tooltip, classNames must be passed through the content slot.

[Download source](/coreai-design-system/source/examples/components-tooltip--styled.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { TooltipProps } from "@coreai-ds/react-components";
import type { JSXElement } from "@coreai-ds/react-components";
import { makeStyles } from "@coreai-ds/react-components";
import { tokens } from "@coreai-ds/react-components";
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { SlideTextRegular } from "@fluentui/react-icons";
import * as React from 'react';

const useStyles = makeStyles({
    tooltip: {
        backgroundColor: tokens.colorBrandBackground,
        color: tokens.colorNeutralForegroundInverted,
    },
});

export const Styled = (props: Partial<TooltipProps>): JSXElement => {
    const styles = useStyles();
    return (<Tooltip withArrow content={{ children: 'Example tooltip', className: styles.tooltip }} relationship="label" {...props}>
      <Button icon={<SlideTextRegular />} size="large"/>
    </Tooltip>);
};

export default Styled;
```

## Target

Source: Fluent, adapted for CoreAI.

The tooltip can be placed relative to a custom element using `positioning.target`. In this example, the
        tooltip points to the icon inside the button, but it could point to any element.

[Download source](/coreai-design-system/source/examples/components-tooltip--target.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import * as React from 'react';
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ArrowRoutingRegular } from "@fluentui/react-icons";

export const Target = (): JSXElement => {
    const [iconRef, setIconRef] = React.useState<HTMLSpanElement | null>(null);
    return (<Tooltip positioning={{ target: iconRef }} withArrow content="This tooltip points to the icon" relationship="description">
      <Button icon={{ ref: setIconRef, children: <ArrowRoutingRegular /> }}>Button with icon</Button>
    </Tooltip>);
};

export default Target;
```

## With Arrow

Source: Fluent, adapted for CoreAI.

The `withArrow` prop causes the tooltip to have an arrow pointing to its target.

[Download source](/coreai-design-system/source/examples/components-tooltip--with-arrow.tsx)

```tsx
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

import type { JSXElement } from "@coreai-ds/react-components";
import { Tooltip } from "@coreai-ds/react-components";
import { Button } from "@coreai-ds/react-components";
import { ArrowStepInRegular } from "@fluentui/react-icons";
import * as React from 'react';

export const WithArrow = (): JSXElement => (<Tooltip withArrow content="Example tooltip with an arrow" relationship="label">
    <Button icon={<ArrowStepInRegular />} size="large"/>
  </Tooltip>);

export default WithArrow;
```

## Resources

- [Figma component](https://www.figma.com/design/eXfSQrRg3poHRgmr0ivN5V/CoreAI-Figma-Library?node-id=168532-852)
- [Fluent guidance](https://fluent2.microsoft.design/components/web/react/core/tooltip/usage)