Aksara UI

Tooltip

Tooltips show a short description of a control on hover or keyboard focus.

import { Tooltip } from '@aksornproject/aksara-ui'

Basic tooltip

Tooltip is a namespace of five parts. Root holds the state, Trigger is the control, Portal draws the floating bubble, and Title and Content fill it.

Trigger renders a <button> with reset classes and opens the tooltip after a 300ms hover. delay changes that. disabled on the Trigger turns off the tooltip, not the control.

The bubble is black, at most 200px wide and 4px from the trigger. It has an arrow by default. Pass withArrow={false} for a plain bubble, as in this demo.

<Tooltip.Root>
  <Tooltip.Trigger
    aria-label="About late submissions"
    className="inline-flex size-size-size-44 items-center justify-center text-color-icon-primary"
  >
    <IconInterfaceEssentialInfoInformationCircle size={20} aria-hidden />
  </Tooltip.Trigger>
  <Tooltip.Portal withArrow={false}>
    <Tooltip.Content>
      Work handed in after the deadline loses 10% per day.
    </Tooltip.Content>
  </Tooltip.Portal>
</Tooltip.Root>

Placement

placement picks the side, top by default. align picks the edge, center by default. The popup flips and shifts at the edge of the viewport.

render on the Trigger swaps the <button> for your own control, here a Button. A render target keeps its own styles.

{placements.map((placement) => (
  <Tooltip.Root key={placement}>
    <Tooltip.Trigger render={<Button variant="secondary-accent" />}>
      {placement}
    </Tooltip.Trigger>
    <Tooltip.Portal placement={placement} align="start" withArrow={false}>
      <Tooltip.Content>Opens on the {placement}</Tooltip.Content>
    </Tooltip.Portal>
  </Tooltip.Root>
))}

Title and colour

variant on Portal is black, the default, or white. The white bubble has a surface fill and a border. Title adds a semibold line above Content. Content takes the Portal variant unless it sets its own.

<Tooltip.Root>
  <Tooltip.Trigger render={<Button variant="secondary-accent" />}>
    Black
  </Tooltip.Trigger>
  <Tooltip.Portal>
    <Tooltip.Title>Auto-save</Tooltip.Title>
    <Tooltip.Content>Drafts save every 30 seconds.</Tooltip.Content>
  </Tooltip.Portal>
</Tooltip.Root>
<Tooltip.Root>
  <Tooltip.Trigger render={<Button variant="secondary-accent" />}>
    White
  </Tooltip.Trigger>
  <Tooltip.Portal variant="white" placement="bottom">
    <Tooltip.Title>Auto-save</Tooltip.Title>
    <Tooltip.Content>Drafts save every 30 seconds.</Tooltip.Content>
  </Tooltip.Portal>
</Tooltip.Root>

Long content

The popup is not hoverable by default, so the pointer cannot move onto it. Pass disableHoverablePopup={false} on Root when the content is long.

The bubble caps its width at 200px. A wider className on Portal also needs max-w-none, as here.

<Tooltip.Root disableHoverablePopup={false}>
  <Tooltip.Trigger render={<Button variant="secondary-accent" />}>
    Grading policy
  </Tooltip.Trigger>
  <Tooltip.Portal withArrow={false} className="w-[320px] max-w-none">
    <Tooltip.Content>
      Quizzes count for 20% of the final grade, homework for 30% and the
      end-of-term exam for 50%. Late work loses 10% per day.
    </Tooltip.Content>
  </Tooltip.Portal>
</Tooltip.Root>

Accessibility

  • The popup has role="tooltip". While it is open, the trigger's aria-describedby points at it.
  • Hover opens after the delay. Keyboard focus opens it only on :focus-visible. Escape closes it and keeps the focus.
  • Touch does not open a tooltip.
  • An icon-only trigger needs an aria-label. The tooltip becomes its description, not its name.
  • Content is descriptive only. Use a popover for links and buttons.
  • The popup portals to body. Put theme and scale attributes on html so it inherits them.

API

Tooltip.Root

Prop

Type

Tooltip.Trigger

Prop

Type

Tooltip.Portal

Prop

Type

Tooltip.Title

Title takes the attributes and the ref of a div. className merges last.

Tooltip.Content

Prop

Type

Edit on GitHub

On this page