Default

Loading interactive example. Full source is available below.

View example source
Download source
// 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;

Resources

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.
API referenceGenerated CoreAI prop and type summaries

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.

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.

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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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

Loading interactive example. Full source is available below.

Download source
// 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;