Tooltip

A short hint that appears while the pointer rests on an element or keyboard focus reaches it. Use it to name an icon button or add one line of context, and keep anything the reader must see on the page itself.

Installation

bash
npx @smicolon/fasla-ui@latest add tooltip

Run init once per project before adding components. See Installation.

Tooltip is built on Base UI, so it needs the @base-ui/react package, and its avatar slot uses avatar. add installs both with the component, and so does the shadcn CLI.

Preview

Hover over the button, or move to it with Tab.

Variants

Six styles, set with variant. primary, the default, suits everyday labels, and secondary is a quieter neutral. info, success, warning and destructive carry the status colours: pick the one that matches what the message means, and make the words clear on their own. radius chooses between 8px corners for standard and 16px for rounded, which reads as a pill on a single line.

primary
secondary
info
success
warning
destructive
primary · rounded
secondary · rounded
info · rounded
success · rounded
warning · rounded
destructive · rounded

Placement

side picks the side of the trigger the tooltip sits on, and the arrow points back at it. top, bottom, left and right are fixed sides of the screen, so left stays put on a right-to-left page. inline-start and inline-end mean the start and end of the line, so they swap sides in Arabic. When there is no room, the tooltip flips to the opposite side. Set arrow to false to drop the arrow.

top
bottom
left
right
inline-start
inline-end
arrow={false}

Content

The text you put inside is the title. description adds a second, less prominent line. icon puts a 16px glyph before the text, in the text colour, and avatar puts a round 12px avatar in the same place, to show who the hint is about. The text wraps at 296px, so a tooltip is at most 320px wide, or 340px with an icon.

description
icon
avatar
296px

Accessibility

  • A tooltip is a visual hint: Base UI gives it no role and does not link it to the trigger. Give the trigger its own accessible name, as visible text or an aria-label, and keep essential information out of the tooltip.
  • It opens as soon as the pointer rests on the trigger or keyboard focus reaches it, and closes when either leaves or when you press Escape.
  • Keep links and buttons out of a tooltip. It closes as focus moves, so nobody can reach them.
  • The status styles add colour, not meaning. Say what kind of message it is in the words, or add an icon that does.
  • The tooltip takes its direction, language and font from the trigger, even though it renders at the end of body. Direction is never a prop.

Props

Tooltip

PropTypeDefaultDescription
openboolean—Shows or hides the tooltip, when controlled.
defaultOpenbooleanfalseShows the tooltip at first.
onOpenChange(open, eventDetails) => void—Called when the tooltip opens or closes.
disabledbooleanfalseStops the tooltip from opening.

TooltipTrigger

PropTypeDefaultDescription
renderReactElement—Replaces the default button with your element, such as a link or a Button.
delaynumber0How long to wait before opening, in milliseconds.

TooltipContent

PropTypeDefaultDescription
variant"primary" | "secondary" | "info" | "success" | "warning" | "destructive""primary"Colour of the tooltip.
radius"standard" | "rounded""standard"8px corners, or 16px: a pill on one line.
side"top" | "bottom" | "left" | "right" | "inline-start" | "inline-end""top"Side of the trigger it sits on. The inline-* sides follow the reading direction.
align"start" | "center" | "end""center"Where along that side it lines up with the trigger.
sideOffsetnumber8Distance from the trigger to the tooltip, in px.
arrowbooleantrueShows the arrow.
descriptionReactNode—A second line under the title.
iconReactNode—A 16px glyph before the text.
avatarOmit<AvatarProps, "size">—Props for an Avatar before the text, always at size 12.
containerHTMLElement—The element the tooltip renders into. Defaults to body.
classNamestring—Extra classes for the tooltip.

Usage

Basic tooltip

tsx
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"

export function ShareTooltip() {
  return (
    <Tooltip>
      <TooltipTrigger>Share</TooltipTrigger>
      <TooltipContent>Copy link</TooltipContent>
    </Tooltip>
  )
}

Name an icon button

tsx
import { Link } from "lucide-react"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"

export function CopyLinkButton() {
  return (
    <Tooltip>
      <TooltipTrigger aria-label="Copy link">
        <Link aria-hidden="true" />
      </TooltipTrigger>
      <TooltipContent>Copy link</TooltipContent>
    </Tooltip>
  )
}

Style, description and icon

tsx
import { Info } from "lucide-react"
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"

export function ShareInfoTooltip() {
  return (
    <Tooltip>
      <TooltipTrigger>Share</TooltipTrigger>
      <TooltipContent
        variant="info"
        side="bottom"
        icon={<Info />}
        description="Anyone with the link can view this file."
      >
        Copy link
      </TooltipContent>
    </Tooltip>
  )
}

With an avatar

tsx
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"

export function LastEditedTooltip() {
  return (
    <Tooltip>
      <TooltipTrigger>Share</TooltipTrigger>
      <TooltipContent
        variant="secondary"
        avatar={{ src: "/avatars/layla.png", name: "" }}
        description="Edited 5 minutes ago"
      >
        Layla Haddad
      </TooltipContent>
    </Tooltip>
  )
}

At the end of the line

tsx
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"

export function EndSideTooltip() {
  return (
    <Tooltip>
      <TooltipTrigger>Share</TooltipTrigger>
      <TooltipContent side="inline-end">Copy link</TooltipContent>
    </Tooltip>
  )
}