Tooltip

Tooltips appear on demand to explain UI elements, clarify functionality, or provide helpful context without permanently occupying screen space. They automatically position themselves relative to their trigger element.

import {Tooltip} from "@qualcomm-ui/react/tooltip"

Overview

The tooltip should be used to provide additional non-essential information. It is linked to an interactive element (the trigger) and will be shown when this element is focused or hovered. Because the tooltip itself can't be focused or tabbed to, it should not contain interactive elements. Only one tooltip can be open at a time.

In general, tooltips should be used sparingly and only contain succinct information. Here are guidelines to help you decide when to use one:

  • When using controls that lack visual labels, like icon buttons.
  • When defining a term or inline item.
  • When additional information may help a user make decisions.
  • When providing more context to an element.

Examples

Simple

The simple API provides a standalone component with built-in layout. The trigger is supplied as a prop, and the content of the tooltip is the children.

<Tooltip trigger={<Button emphasis="primary">Hover me</Button>}>
  Hello world!
</Tooltip>

Composite

Build with the composite API for granular control. This API requires you to provide each subcomponent, but gives you full control over the structure and layout.

<Tooltip.Root>
  <Tooltip.Trigger>
    <Button emphasis="primary">Hover me</Button>
  </Tooltip.Trigger>
  <Portal>
    <Tooltip.Positioner>
      <Tooltip.Content>
        <Tooltip.Arrow>
          <Tooltip.ArrowTip />
        </Tooltip.Arrow>
        Hello world!
      </Tooltip.Content>
    </Tooltip.Positioner>
  </Portal>
</Tooltip.Root>

Placement

The tooltip's position, relative to the trigger element, can be set using the placement option of the positioning prop. Its default value is top. Change the values in the example below and hover over the select to see the tooltip position change.

import {type ReactElement, useState} from "react"

import {selectCollection} from "@qualcomm-ui/core/select"
import type {Placement} from "@qualcomm-ui/dom/floating-ui"
import {Select} from "@qualcomm-ui/react/select"
import {Tooltip} from "@qualcomm-ui/react/tooltip"

const positions = selectCollection({
  items: [
    "top-start",
    "top",
    "top-end",
    "right-start",
    "right",
    "right-end",
    "bottom-start",
    "bottom",
    "bottom-end",
    "left-start",
    "left",
    "left-end",
  ],
})

export function TooltipPlacementDemo(): ReactElement {
  const [placement, setPlacement] = useState<Placement>("top")

  return (
    <div className="w-48">
      <Tooltip
        positioning={{placement}}
        trigger={
          <Select
            aria-label="Select a position"
            collection={positions}
            onValueChange={(value) => setPlacement(value[0] as Placement)}
            positioning={{sameWidth: true}}
            value={[placement]}
          />
        }
      >
        {placement}
      </Tooltip>
    </div>
  )
}

Close On Click / Escape

By default, the tooltip will close when the Escape key is pressed or a click is detected. You can customize this behavior by using the closeOnClick and closeOnEscape props.

<Tooltip
  closeOnClick={false}
  closeOnEscape={false}
  trigger={<Button emphasis="primary">Hover me</Button>}
>
  Hello world!
</Tooltip>

Controlled Visibility

Set the initial visibility using the defaultOpen prop, or use open and onOpenChange to control the visibility manually. These props follow our controlled state pattern.

The tooltip is hidden
import {type ReactElement, useState} from "react"

import {Button} from "@qualcomm-ui/react/button"
import {Tooltip} from "@qualcomm-ui/react/tooltip"

export function TooltipControlledStateDemo(): ReactElement {
  const [open, setOpen] = useState(false)

  return (
    <div className="flex w-40 flex-col items-center gap-4">
      <Tooltip
        onOpenChange={setOpen}
        open={open}
        trigger={<Button emphasis="primary">Hover me</Button>}
      >
        Hello world!
      </Tooltip>

      <output className="font-body-sm text-neutral-primary flex">
        The tooltip is {open ? "visible" : "hidden"}
      </output>
    </div>
  )
}

Disabled

You can disable the tooltip by using the disabled prop.

import {type ReactElement, useState} from "react"

import {Button} from "@qualcomm-ui/react/button"
import {Tooltip} from "@qualcomm-ui/react/tooltip"

export function TooltipDisabledDemo(): ReactElement {
  const [disabled, setDisabled] = useState(true)
  return (
    <div className="flex flex-col items-center gap-4">
      <Tooltip
        disabled={disabled}
        trigger={<Button emphasis="primary">Hover me</Button>}
      >
        Hello world!
      </Tooltip>

      <Button onClick={() => setDisabled(!disabled)} variant="outline">
        {disabled ? "Enable" : "Disable"} tooltip
      </Button>
    </div>
  )
}

Shortcuts

Shortcuts are enabled for common use cases.

Arrow

If you don't wish to customize the arrow tip, you can omit it and Tooltip.Arrow will render the default one. At that, <Tooltip.Arrow /> is equivalent to:

<Tooltip.Arrow>
  <Tooltip.ArrowTip />
</Tooltip.Arrow>

API

<Tooltip>

The simple tooltip extends the Tooltip.Root component with the following props:

PropTypeDefault
React children render prop. The tooltip trigger event handlers and attributes are applied to this element. It must forward its ref
Props applied to the arrow element.
Props applied to the arrow tip element.
Props applied to the content element.
Whether to hide the arrow.
boolean
false
Props applied to the portal element.
PortalProps
Props applied to the positioner element.
Description
React children render prop. The tooltip trigger event handlers and attributes are applied to this element. It must forward its ref
Description
Props applied to the arrow element.
Description
Props applied to the arrow tip element.
Description
Props applied to the content element.
Type
boolean
Description
Whether to hide the arrow.
Type
PortalProps
Description
Props applied to the portal element.
Description
Props applied to the positioner element.

Composite API

<Tooltip.Root>

The main component that wraps the trigger and the content elements. Doesn't render anything by itself.
PropTypeDefault
React children prop.
Whether the tooltip should close when the trigger is clicked.
boolean
Whether the tooltip should close when the escape key is pressed.
boolean
The document's text/writing direction.
'ltr' | 'rtl'
'ltr'
Controls the component's interactivity. If true, the component's trigger element will not activate the tooltip.
boolean
Function called when the tooltip is opened/closed.
    (
    open: boolean,
    ) => void
    The open state of the tooltip.
    boolean
    The user provided options used to position the popover content
    Description
    React children prop.
    Type
    boolean
    Description
    Whether the tooltip should close when the trigger is clicked.
    Type
    boolean
    Description
    Whether the tooltip should close when the escape key is pressed.
    Type
    'ltr' | 'rtl'
    Description
    The document's text/writing direction.
    Type
    boolean
    Description
    Controls the component's interactivity. If true, the component's trigger element will not activate the tooltip.
    Type
    (
    open: boolean,
    ) => void
    Description
    Function called when the tooltip is opened/closed.
      Type
      boolean
      Description
      The open state of the tooltip.
      Description
      The user provided options used to position the popover content

      <Tooltip.Trigger>

      A trigger that opens the tooltip. Doesn't render anything by itself. Applies event handlers and attributes to the child element.
      PropType
      React children Render Prop
      id attribute. If omitted, a unique identifier will be automatically generated for accessibility.
      string
      Type
      string
      Description
      id attribute. If omitted, a unique identifier will be automatically generated for accessibility.

      <Tooltip.Positioner>

      The element that positions the tooltip content relative to the trigger. Renders a <div> element by default.
      PropType
      React children prop.
      id attribute. If omitted, a unique identifier will be automatically generated for accessibility.
      string
      Allows you to replace the component's HTML element with a different tag or component. Learn more
      | ReactElement
      | ((
      props: object,
      ) => ReactElement)
      Description
      React children prop.
      Type
      string
      Description
      id attribute. If omitted, a unique identifier will be automatically generated for accessibility.
      Type
      | ReactElement
      | ((
      props: object,
      ) => ReactElement)
      Description
      Allows you to replace the component's HTML element with a different tag or component. Learn more

      <Tooltip.Content>

      The content of the tooltip which is displayed relative to the trigger. Renders a <div> element by default.
      PropType
      React children prop.
      id attribute. If omitted, a unique identifier will be automatically generated for accessibility.
      string
      Allows you to replace the component's HTML element with a different tag or component. Learn more
      | ReactElement
      | ((
      props: object,
      ) => ReactElement)
      Description
      React children prop.
      Type
      string
      Description
      id attribute. If omitted, a unique identifier will be automatically generated for accessibility.
      Type
      | ReactElement
      | ((
      props: object,
      ) => ReactElement)
      Description
      Allows you to replace the component's HTML element with a different tag or component. Learn more

      <Tooltip.Arrow>

      The container that positions the arrow. This element renders the <Tooltip.ArrowTip/> by default if no children are provided.
      PropType
      React children prop.
      Allows you to replace the component's HTML element with a different tag or component. Learn more
      | ReactElement
      | ((
      props: object,
      ) => ReactElement)
      Description
      React children prop.
      Type
      | ReactElement
      | ((
      props: object,
      ) => ReactElement)
      Description
      Allows you to replace the component's HTML element with a different tag or component. Learn more

      <Tooltip.ArrowTip>

      The arrow tip element. Renders a <div> element by default.
      PropType
      Allows you to replace the component's HTML element with a different tag or component. Learn more
      | ReactElement
      | ((
      props: object,
      ) => ReactElement)
      Type
      | ReactElement
      | ((
      props: object,
      ) => ReactElement)
      Description
      Allows you to replace the component's HTML element with a different tag or component. Learn more

      TooltipPositioningOptions

      PropTypeDefault
      The minimum padding between the arrow and the floating element's corner.
      number
      10
      
      The overflow boundary of the reference element
        () =>
        | 'clippingAncestors'
        | Element
        | Array<Element>
        | {
        height: number
        width: number
        x: number
        y: number
        }
        Whether the popover should fit the viewport.
        boolean
        Whether to flip the placement when the floating element overflows the boundary.
        | boolean
        | Array<
        | 'bottom'
        | 'bottom-end'
        | 'bottom-start'
        | 'left'
        | 'left-end'
        | 'left-start'
        | 'right'
        | 'right-end'
        | 'right-start'
        | 'top'
        | 'top-end'
        | 'top-start'
        >
        true
        
        Function that returns the anchor rect
          (
          element:
          | HTMLElement
          | VirtualElement,
          ) => {
          height?: number
          width?: number
          x?: number
          y?: number
          }
          The main axis offset or gap between the reference and floating element
          number
          8
          
          Whether the popover should be hidden when the reference element is detached
          boolean
          Options to activate auto-update listeners
          | boolean
          | {
          ancestorResize?: boolean
          ancestorScroll?: boolean
          animationFrame?: boolean
          elementResize?: boolean
          layoutShift?: boolean
          }
          true
          
          The offset of the floating element
          {
          crossAxis?: number
          mainAxis?: number
          }
          Function called when the placement is computed
            (
            data: ComputePositionReturn,
            ) => void
            Function called when the floating element is positioned or not
              (data: {
              placed: boolean
              }) => void
              The virtual padding around the viewport edges to check for overflow
              number
              Whether the floating element can overlap the reference element
              boolean
              false
              
              The initial placement of the floating element
              | 'bottom'
              | 'bottom-end'
              | 'bottom-start'
              | 'left'
              | 'left-end'
              | 'left-start'
              | 'right'
              | 'right-end'
              | 'right-start'
              | 'top'
              | 'top-end'
              | 'top-start'
              'top'
              
              Whether to make the floating element same width as the reference element
              boolean
              The secondary axis offset or gap between the reference and floating elements
              number
              Whether the popover should slide when it overflows.
              boolean
              The strategy to use for positioning
              | 'absolute'
              | 'fixed'
              'absolute'
              
              A callback that will be called when the popover needs to calculate its position.
                (data: {
                updatePosition: () => Promise<void>
                }) => void | Promise<void>
                Type
                number
                Description
                The minimum padding between the arrow and the floating element's corner.
                Type
                () =>
                | 'clippingAncestors'
                | Element
                | Array<Element>
                | {
                height: number
                width: number
                x: number
                y: number
                }
                Description
                The overflow boundary of the reference element
                  Type
                  boolean
                  Description
                  Whether the popover should fit the viewport.
                  Type
                  | boolean
                  | Array<
                  | 'bottom'
                  | 'bottom-end'
                  | 'bottom-start'
                  | 'left'
                  | 'left-end'
                  | 'left-start'
                  | 'right'
                  | 'right-end'
                  | 'right-start'
                  | 'top'
                  | 'top-end'
                  | 'top-start'
                  >
                  Description
                  Whether to flip the placement when the floating element overflows the boundary.
                  Type
                  (
                  element:
                  | HTMLElement
                  | VirtualElement,
                  ) => {
                  height?: number
                  width?: number
                  x?: number
                  y?: number
                  }
                  Description
                  Function that returns the anchor rect
                    Type
                    number
                    Description
                    The main axis offset or gap between the reference and floating element
                    Type
                    boolean
                    Description
                    Whether the popover should be hidden when the reference element is detached
                    Type
                    | boolean
                    | {
                    ancestorResize?: boolean
                    ancestorScroll?: boolean
                    animationFrame?: boolean
                    elementResize?: boolean
                    layoutShift?: boolean
                    }
                    Description
                    Options to activate auto-update listeners
                    Type
                    {
                    crossAxis?: number
                    mainAxis?: number
                    }
                    Description
                    The offset of the floating element
                    Type
                    (
                    data: ComputePositionReturn,
                    ) => void
                    Description
                    Function called when the placement is computed
                      Type
                      (data: {
                      placed: boolean
                      }) => void
                      Description
                      Function called when the floating element is positioned or not
                        Type
                        number
                        Description
                        The virtual padding around the viewport edges to check for overflow
                        Type
                        boolean
                        Description
                        Whether the floating element can overlap the reference element
                        Type
                        | 'bottom'
                        | 'bottom-end'
                        | 'bottom-start'
                        | 'left'
                        | 'left-end'
                        | 'left-start'
                        | 'right'
                        | 'right-end'
                        | 'right-start'
                        | 'top'
                        | 'top-end'
                        | 'top-start'
                        Description
                        The initial placement of the floating element
                        Type
                        boolean
                        Description
                        Whether to make the floating element same width as the reference element
                        Type
                        number
                        Description
                        The secondary axis offset or gap between the reference and floating elements
                        Type
                        boolean
                        Description
                        Whether the popover should slide when it overflows.
                        Type
                        | 'absolute'
                        | 'fixed'
                        Description
                        The strategy to use for positioning
                        Type
                        (data: {
                        updatePosition: () => Promise<void>
                        }) => void | Promise<void>
                        Description
                        A callback that will be called when the popover needs to calculate its position.