Tooltips

Communication components provide helpful information

Usage

A tooltip provides additional context for a UI element.

Instalation

Run the following command:

npm i @radix-ui/react-tooltip

Copy and paste the following code into your project.

'use client'

import * as React from 'react'
import * as TooltipPrimitive from '@radix-ui/react-tooltip'
import { cva, type VariantProps } from 'class-variance-authority'

import { cn } from '@/lib/utils'

const tooltipVariants = cva(
  'z-50 overflow-hidden max-w-[230px] animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
  {
    variants: {
      variant: {
        plain:
          'rounded-xs bg-inverseSurface text-inverseOnSurface text-body-sm px-2 py-1',
        rich: 'rounded-md bg-surfaceContainer px-4 pb-2 pt-3 shadow-sm',
      },
    },
    defaultVariants: {
      variant: 'plain',
    },
  }
)

const TooltipProvider = TooltipPrimitive.Provider

const TooltipRoot = TooltipPrimitive.Root

const TooltipTrigger = TooltipPrimitive.Trigger

interface TooltipContainerProps
  extends React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>,
    VariantProps<typeof tooltipVariants> {}

const TooltipContent = React.forwardRef<
  React.ElementRef<typeof TooltipPrimitive.Content>,
  TooltipContainerProps
>(({ className, sideOffset = 4, variant, ...props }, ref) => (
  <TooltipPrimitive.Content
    ref={ref}
    sideOffset={sideOffset}
    className={cn(tooltipVariants({ variant, className }))}
    {...props}
  />
))
TooltipContent.displayName = TooltipPrimitive.Content.displayName

const TooltipSubhead = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
  <p
    ref={ref}
    className={cn('mb-1 text-title-sm text-onSurfaceVariant', className)}
    {...props}
  />
))

const TooltipSupportingText = React.forwardRef<
  HTMLParagraphElement,
  React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
  <p
    ref={ref}
    className={cn('mb-1 text-body-md text-onSurfaceVariant', className)}
    {...props}
  />
))

const TooltipActionContainer = React.forwardRef<
  HTMLDivElement,
  React.HTMLAttributes<HTMLDivElement>
>(({ className, ...props }, ref) => (
  <div
    ref={ref}
    className={cn('-ml-2 mt-2 flex items-center gap-x-2', className)}
    {...props}
  />
))

const Tooltip = Object.assign(TooltipRoot, {
  Provider: TooltipProvider,
  Trigger: TooltipTrigger,
  Content: TooltipContent,
  Subhead: TooltipSubhead,
  SupportingText: TooltipSupportingText,
  ActionsContainer: TooltipActionContainer,
})

export {
  Tooltip,
  TooltipRoot,
  TooltipTrigger,
  TooltipContent,
  TooltipSubhead,
  TooltipSupportingText,
  TooltipActionContainer,
}

Update the import paths to match your project setup.

Examples

Plain tooltip

Plain tooltips briefly describe a UI element. They’re best used for labelling UI elements with no text, like icon-only buttons and fields.

import { Icon } from '@/components/ui/icon'
import { IconButton } from '@/components/ui/icon-button'
import { Tooltip } from '@/components/ui/tooltip'

export const PlainTooltip = () => {
  return (
    <Tooltip.Provider>
      <Tooltip>
        <Tooltip.Trigger asChild>
          <IconButton variant="standard">
            <Icon symbol="notifications" />
          </IconButton>
        </Tooltip.Trigger>
        <Tooltip.Content>Notifications</Tooltip.Content>
      </Tooltip>
    </Tooltip.Provider>
  )
}

Rich tooltip

Rich tooltips provide additional context about a UI element. They can optionally contain a subhead, buttons, and hyperlinks.

Rich tooltips are best used for longer text like definitions or explanations.

import { Icon } from '@/components/ui/icon'
import { IconButton } from '@/components/ui/icon-button'
import { Tooltip } from '@/components/ui/tooltip'

export const RichTooltip = () => {
  return (
    <Tooltip.Provider>
      <Tooltip>
        <Tooltip.Trigger asChild>
          <IconButton variant="standard">
            <Icon symbol="brush" />
          </IconButton>
        </Tooltip.Trigger>
        <Tooltip.Content
          variant="rich"
          side="right"
          align="start"
          alignOffset={40}
          sideOffset={0}
        >
          <Tooltip.Subhead>Paint Tool</Tooltip.Subhead>
          <Tooltip.SupportingText>
            Add annotation and highlights with the paint tool.
          </Tooltip.SupportingText>
          <Tooltip.ActionsContainer>
            <Button variant="text">Learn more</Button>
          </Tooltip.ActionsContainer>
        </Tooltip.Content>
      </Tooltip>
    </Tooltip.Provider>
  )
}