useTooltipTrigger

Provides the behavior and accessibility implementation for a tooltip trigger, e.g. a button that shows a description when focused or hovered.

installyarn add @react-aria/tooltip
version3.0.0
usageimport {useTooltipTrigger, useTooltip} from '@react-aria/tooltip'

API#


useTooltipTrigger( props: TooltipTriggerProps, state: TooltipTriggerState, ref: RefObject<HTMLElement> ): TooltipTriggerAriauseTooltip( (props: AriaTooltipProps )): TooltipAria

Features#


The HTML title attribute can be used to create a tooltip, but it cannot be styled. Custom styled tooltips can be hard to build in an accessible way. useTooltipTrigger and useTooltip help build fully accessible tooltips that can be styled as needed.

  • Keyboard focus management and cross browser normalization
  • Hover management and cross browser normalization
  • Labeling support for screen readers (aria-describedby)
  • Exposed as a tooltip to assistive technology via ARIA
  • Matches native tooltip behavior with delay on hover of first tooltip and no delay on subsequent tooltips.

Anatomy#


A tooltip consists of two parts, the trigger element and the tooltip itself. Users may reveal the tooltip by hovering or focusing the trigger.

useTooltipTrigger returns props to be spread onto its target trigger and the tooltip:

NameTypeDescription
triggerPropsHTMLAttributes<HTMLElement>PressPropsHoverPropsFocusEventsProps for the trigger element.
tooltipPropsHTMLAttributes<HTMLElement>Props for the overlay container element.

useTooltip returns props to be spread onto the tooltip:

NameTypeDescription
tooltipPropsHTMLAttributes<HTMLElement>Props for the tooltip element.

Tooltip state is managed by the useTooltipTriggerState hook in @react-stately/tooltip. The state object should be passed as an option to useTooltipTrigger.

Example#


This example implements a Tooltip that renders in an absolute position next to its target. The useTooltip hook applies the correct ARIA attributes to the tooltip, and useTooltipTrigger associates it to the trigger element.

Two instances of the example are rendered to demonstrate the behavior of the delay on hover. If you hover over the first button, the tooltip will be shown after a delay. Hovering over the second button shows the tooltip immediately. If you wait for a delay before hovering another element, the delay restarts.

import {useTooltipTriggerState} from '@react-stately/tooltip';
import {mergeProps} from '@react-aria/utils';

function Tooltip(props) {
  let {tooltipProps} = useTooltip(props);

  return (
    <span
      style={{
        position: 'absolute',
        left: '5px',
        top: '100%',
        marginTop: '10px',
        backgroundColor: 'white',
        color: 'black',
        padding: '5px'
      }}
      {...mergeProps(props, tooltipProps)}>
      {props.children}
    </span>
  );
}

function Example(props) {
  let state = useTooltipTriggerState(props);
  let ref = React.useRef();

  // Get props for the trigger and its tooltip
  let {triggerProps, tooltipProps} = useTooltipTrigger(props, state, ref);

  return (
    <span style={{position: 'relative'}}>
      <button ref={ref} {...triggerProps}>
        I have a tooltip
      </button>
      {state.isOpen && (
        <Tooltip {...tooltipProps}>
          And the tooltip tells you more information.
        </Tooltip>
      )}
    </span>
  );
}

<Example />
<Example />
import {useTooltipTriggerState} from '@react-stately/tooltip';
import {mergeProps} from '@react-aria/utils';

function Tooltip(props) {
  let {tooltipProps} = useTooltip(props);

  return (
    <span
      style={{
        position: 'absolute',
        left: '5px',
        top: '100%',
        marginTop: '10px',
        backgroundColor: 'white',
        color: 'black',
        padding: '5px'
      }}
      {...mergeProps(props, tooltipProps)}>
      {props.children}
    </span>
  );
}

function Example(props) {
  let state = useTooltipTriggerState(props);
  let ref = React.useRef();

  // Get props for the trigger and its tooltip
  let {triggerProps, tooltipProps} = useTooltipTrigger(
    props,
    state,
    ref
  );

  return (
    <span style={{position: 'relative'}}>
      <button ref={ref} {...triggerProps}>
        I have a tooltip
      </button>
      {state.isOpen && (
        <Tooltip {...tooltipProps}>
          And the tooltip tells you more information.
        </Tooltip>
      )}
    </span>
  );
}

<Example />
<Example />
import {useTooltipTriggerState} from '@react-stately/tooltip';
import {mergeProps} from '@react-aria/utils';

function Tooltip(props) {
  let {
    tooltipProps
  } = useTooltip(props);

  return (
    <span
      style={{
        position:
          'absolute',
        left: '5px',
        top: '100%',
        marginTop:
          '10px',
        backgroundColor:
          'white',
        color: 'black',
        padding: '5px'
      }}
      {...mergeProps(
        props,
        tooltipProps
      )}>
      {props.children}
    </span>
  );
}

function Example(props) {
  let state = useTooltipTriggerState(
    props
  );
  let ref = React.useRef();

  // Get props for the trigger and its tooltip
  let {
    triggerProps,
    tooltipProps
  } = useTooltipTrigger(
    props,
    state,
    ref
  );

  return (
    <span
      style={{
        position:
          'relative'
      }}>
      <button
        ref={ref}
        {...triggerProps}>
        I have a tooltip
      </button>
      {state.isOpen && (
        <Tooltip
          {...tooltipProps}>
          And the tooltip
          tells you more
          information.
        </Tooltip>
      )}
    </span>
  );
}

<Example />
<Example />

Internationalization#


RTL#

In right-to-left languages, tooltips should be mirrored across trigger. Ensure that your CSS and overlay positioning (if any) accounts for this.