Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Overlays

Tooltip

Overlays

Tooltip React component for Tailwind CSS v4

Shortcuts DialogTour
Live props
Content
content
shortcut
Appearance
tone
color
size
radius
arrow
Layout
side
align
sideOffset6px
Behavior
delayDuration300ms
longPress
touchDuration1500ms
overflowOnly
State
defaultOpen
disabled
Code
import { Tooltip } from "@/components/ui/tooltip"

<Tooltip />
  1. Home
  2. Components
  3. Overlays
  4. Tooltip
Free

Tooltip React component for Tailwind CSS v4

v1.0.0·Added in 1.0.0

A React tooltip for icon buttons and cut-off text: shortcut hints, toolbar groups that skip the delay and a long press on touch.

Rest the pointer on a trigger and after 300ms the label fades in, growing a touch out of the trigger. Inside a TooltipGroup only the first one waits: glide along a toolbar and each next label swaps in at once. Tab to a trigger and its tooltip opens straight away; Escape, a click, a scroll or moving away closes it. The pointer can travel onto the tooltip without closing it. A shortcut shows after the text in the notation of your device (⌘C on a Mac, Ctrl+C elsewhere) and is announced as aria-keyshortcuts. Phones have no hover, so a long press shows the label instead: the button does not fire, the tooltip stays while your finger is down and for 1.5 seconds after, and the next touch dismisses it. Shortcut hints hide on touch screens. With reduced motion it only fades.

Tooltip is a free React component in the React overlay components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add tooltip, together with Kbd, useControllableState, useLongPress, useShortcut, Motion presets and 2 more and the npm packages @radix-ui/react-tooltip, @radix-ui/react-slot and motion.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add tooltip

Usage

Import Tooltip from @/components/ui/tooltip.

import { Copy, Heart, Share2 } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Tooltip, TooltipGroup } from "@/components/ui/tooltip"

export function ListingActions({ onSave, onCopy }: { onSave: () => void; onCopy: () => void }) {
  return (
    <TooltipGroup>
      <div className="flex items-center gap-1">
        <Tooltip content="Save to favorites" shortcut="s">
          <Button variant="ghost" size="icon" radius="full" aria-label="Save to favorites" onClick={onSave}>
            <Heart />
          </Button>
        </Tooltip>
        <Tooltip content="Share">
          <Button variant="ghost" size="icon" radius="full" aria-label="Share">
            <Share2 />
          </Button>
        </Tooltip>
        <Tooltip content="Copy link" shortcut="mod+c" side="bottom" arrow>
          <Button variant="ghost" size="icon" radius="full" aria-label="Copy link" onClick={onCopy}>
            <Copy />
          </Button>
        </Tooltip>
      </div>
    </TooltipGroup>
  )
}

// a value that only shows its tooltip when it is cut off
export function Address({ value }: { value: string }) {
  return (
    <Tooltip content={value} overflowOnly>
      <span tabIndex={0} className="block max-w-40 truncate">
        {value}
      </span>
    </Tooltip>
  )
}

Props

  • contentdefault ""
    ReactNode

    The label: a few words for an icon button, or a sentence with size md. Empty renders the trigger alone, so a tooltip can come and go without re-mounting the button.

  • shortcutdefault ""
    string

    A combo in mod+k notation ("s", "mod+c", "alt+n", "shift+mod+p"), shown after the text at 60% of its color and set as aria-keyshortcuts on the trigger. Display only: bind the key yourself with useShortcut. Hidden on touch screens.

  • children
    ReactNode

    The trigger, rendered asChild: a Button, an <a>, or a span with tabIndex={0}. It must pass a ref to its element. A disabled <button> gets no pointer events, so wrap it in a focusable span. A plain string gets a focusable span of its own. It keeps its own data-slot and data-state; the tooltip's state is in data-tooltip-state.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    neutral is the inverted tooltip: black on a light page, near-white on a dark one. Other tones fill with their color, for a label that carries meaning (out of stock, verified).

  • colordefault ""
    string

    Any CSS color. Replaces the tone; the text turns black or white by lightness. Leave empty to use the tone.

  • sizedefault "sm"
    "sm" | "md"

    sm is one short centered line in 12px medium type, up to 256px wide. md is for a sentence: 13px, more padding, left aligned, up to 288px wide. Both shrink to the room left on screen, so a flipped tooltip wraps on a phone instead of running off the edge.

  • radiusdefault "md"
    "none" | "sm" | "md" | "lg" | "full"

    Corner shape, scaled with the size: md is 8px on sm and 10px on md. full is a pill on one line and a soft capsule on a wrapped sentence.

  • arrowdefault false
    boolean

    A small arrow with a rounded tip in the tooltip's color, pointing at the center of the trigger and kept clear of the corners.

  • sidedefault "top"
    "top" | "right" | "bottom" | "left"

    Where it opens. It flips to the opposite side and slides along the edge when there is no room.

  • aligndefault "center"
    "start" | "center" | "end"

    Alignment along the trigger's edge.

  • sideOffsetdefault 6
    number

    Distance from the trigger in px. The arrow adds its own height on top.

  • delayDurationdefault 300
    number

    Hover time in ms before it opens. Keyboard focus opens it at once. Inside a TooltipGroup the group's delay wins (the playground feeds this value to the group).

  • longPressdefault true
    boolean

    On touch screens a long press on the trigger shows the tooltip, with a light vibration where supported. The click that would follow is swallowed, so the button does not fire. Off: touch never shows it.

  • touchDurationdefault 1500
    number

    How long in ms it stays after the finger lifts from a long press. The next touch anywhere closes it sooner.

  • overflowOnlydefault false
    boolean

    Opens only while the trigger's text is cut off (truncate or line-clamp on the trigger or inside it), so a cell shows its full value only when it needs to. The playground's heart never overflows, so it stays quiet.

  • defaultOpendefault false
    boolean

    Starts open. The next hover elsewhere, click or scroll closes it.

  • disableddefault false
    boolean

    Never opens and closes if it is open. The trigger itself keeps working.

  • open
    boolean

    Controls it from outside, with onOpenChange. Handy for a confirmation like "Link copied" after a click.

  • onOpenChange
    (open: boolean) => void

    Called on hover, focus, long press, Escape, click and scroll. Not called for opens that are refused (disabled, overflowOnly with nothing cut off, a tap on a touch screen).

  • container
    HTMLElement | null

    Where the portal mounts. document.body by default.

  • classNames
    Partial<Record<"content" | "arrow" | "shortcut", string>>

    Extra classes for the tooltip body, the arrow svg and the shortcut Kbd.

  • className
    string

    Extra classes for the tooltip body (the trigger is your child), merged last. Other Radix content props (alignOffset, collisionPadding, avoidCollisions, onEscapeKeyDown, aria-label) pass through.

Parts

  • TooltipGroup

    component

    Wrap a toolbar: the first tooltip waits delayDuration (300), then moving to the next within skipDelayDuration (300) opens it at once with a quick fade. Tooltips outside a group bring their own provider, so no setup is needed. Props: { delayDuration?: number; skipDelayDuration?: number; disableHoverableContent?: boolean; children }.

  • TooltipRoot

    component

    State and behavior for the parts: open, defaultOpen, onOpenChange, delayDuration, disabled, longPress, touchDuration, overflowOnly, shortcut, disableHoverableContent. Props: TooltipRootProps.

  • TooltipTrigger

    component

    Wires hover, focus and long press onto its child (asChild) or its own <button>, and sets aria-keyshortcuts. Props: ComponentProps<"button"> & { asChild?: boolean }.

  • TooltipContent

    component

    The portaled, animated body: side, align, sideOffset, arrow, tone, color, size, radius, container, classNames and the Radix content props. Renders the Root's shortcut after its children. Props: TooltipContentProps.

Examples

Sides and alignments

Four sides, three alignments, with the arrow. It flips and slides when there is no room.

Tones and a custom color

Neutral is inverted in both themes; a tone or any CSS color for labels that carry meaning.

Shortcut hints

The combo in the device's notation after the text; the app binds it. Try the keys.

On toggles

The trigger keeps its own data-state, so a pressed toggle stays pressed under its tooltip. The shortcuts work too.

A sentence with size md

13px, left aligned, up to 288px wide: the fee explained next to a price summary. Touch screens show the note inline instead.

Cut-off values

overflowOnly shows the full text only when truncate actually cut it.

On a disabled button

A disabled button gets no pointer events: a focusable span carries the tooltip. Touch screens also show the reason inline.

Long press on a phone

An icon-only photo toolbar. On touch a long press reads the label; touchDuration keeps it 2s.

Dependencies

@radix-ui/react-tooltip@radix-ui/react-slotmotionkbduse-controllable-stateuse-long-pressuse-shortcutmotiontonesui-config

Files

  • components/ui/tooltip.tsx

FAQ

Is the React Tooltip component free?

Yes. The source is free and needs no account: copy it from the Code tab or install it with the CLI.

How do I install Tooltip?

Run npx wingo-ui@latest add tooltip. It also adds the Wingo UI items it builds on (Kbd, useControllableState, useLongPress, useShortcut, Motion presets and 2 more) and the npm packages @radix-ui/react-tooltip, @radix-ui/react-slot and motion. With shadcn, run npx shadcn@latest add https://wingo-ui.com/r/tooltip.json.

See also

KbdHover CardPopoverButtonuseLongPresshookuseShortcuthook

Used in

QR CodePowerPoint ViewerFavorite buttonVideo PlayerFile managerImage CropperLocation MapStat CardWorkflow CanvasVoice InputSegmented ControlAudio Player

and 45 more.

More React overlay components

Dropdown MenuAlert DialogContext MenuDialogDrawerFamily Drawer
All 13 React overlay components
PreviousShortcuts DialogNext Tour
White Trek FX 2 city bike leaning on a wall1 / 8

City bike, Trek FX 2

New York · today, 2:20 PM

$320

Hover the heart, then glide along the toolbar: the next labels open instantly. Press SS to save.

Long press a button to read its label; the button does not fire.

delay 300ms · long press 1.5s