react ~7 KB 0 deps v0.4.0 ↗ GitHub ↗

@mshafiqyajid/react-tooltip

Headless tooltip hook and styled component for React. Accessible, keyboard-friendly, full placement set with -start/-end alignment, flip + shift + offset + collisionPadding, interactive mode, cursor-follow mode, touch long-press, group keyboard navigation, header/footer slots, SSR-safe, fully typed.

Playground #

Props
TSX
import { TooltipStyled } from "@mshafiqyajid/react-tooltip/styled";
import "@mshafiqyajid/react-tooltip/styles.css";

<TooltipStyled
  content="Copy to clipboard"
/>

TooltipProvider — sweep / delay group

First tooltip opens after 700ms. Once one is open, sweep to the others instantly.

Install #

npm install @mshafiqyajid/react-tooltip

Quick start #

import { TooltipStyled } from "@mshafiqyajid/react-tooltip/styled";
import "@mshafiqyajid/react-tooltip/styles.css";

export function App() {
  return (
    <TooltipStyled content="Copy to clipboard" placement="top">
      <button>Copy</button>
    </TooltipStyled>
  );
}

Placements #

Each side accepts an optional -start or -end alignment. The tooltip automatically flips to the opposite side near viewport edges (toggle with flip) and shifts back into view along the cross-axis (toggle with shift).

<TooltipStyled content="Top start"  placement="top-start">...</TooltipStyled>
<TooltipStyled content="Bottom end" placement="bottom-end">...</TooltipStyled>
<TooltipStyled content="Right" placement="right" offset={12} collisionPadding={16}>
  ...
</TooltipStyled>

Tones #

<TooltipStyled content="Neutral" tone="neutral">...</TooltipStyled>
<TooltipStyled content="Primary" tone="primary">...</TooltipStyled>
<TooltipStyled content="Success" tone="success">...</TooltipStyled>
<TooltipStyled content="Danger" tone="danger">...</TooltipStyled>

Rich content #

Pass any JSX to content. Use multiline to allow text to wrap.

<TooltipStyled
  multiline
  content={
    <span>
      <strong>⌘ + C</strong> to copy
    </span>
  }
>
  <button>Copy</button>
</TooltipStyled>

Delay #

Show delay defaults to 0 (instant). Increase for less sensitive triggers. Wrap tooltips in TooltipProvider to set a shared delay and get instant switching between hovered tooltips.

<TooltipStyled content="Appears after 500ms" delay={500}>...</TooltipStyled>

// Shared delay via provider
import { TooltipProvider } from "@mshafiqyajid/react-tooltip/styled";
<TooltipProvider delay={300}>
  <TooltipStyled content="Fast switch">...</TooltipStyled>
  <TooltipStyled content="Fast switch too">...</TooltipStyled>
</TooltipProvider>

Interactive tooltip #

Set interactive to keep the tooltip open while the cursor is over it (e.g. for clickable links inside the tooltip). A 50 ms bridge prevents accidental close on cursor transition.

<TooltipStyled
  interactive
  content={<a href="/docs">Read the docs</a>}
>
  <button>Help</button>
</TooltipStyled>

Cursor-following #

Set followCursor to anchor the tooltip to the cursor position instead of the trigger. Useful for data visualisation hover labels.

<TooltipStyled content="Position: hover" followCursor>
  <div className="chart-area">...</div>
</TooltipStyled>
<TooltipStyled
  header={<strong>Keyboard shortcut</strong>}
  content="Copies the selection to clipboard"
  footer={<kbd>⌘ C</kbd>}
>
  <button>Copy</button>
</TooltipStyled>

Group navigation #

Tooltips sharing a group key are linked: pressing ↓/↑ on a focused trigger cycles to the next/previous group member. Useful for guided tours.

<TooltipStyled group="tour" content="Step 1: Click here first">
  <button>Step 1</button>
</TooltipStyled>
<TooltipStyled group="tour" content="Step 2: Then click this">
  <button>Step 2</button>
</TooltipStyled>

Headless #

Use useTooltip to build a fully custom tooltip with your own markup and styles.

import { useTooltip } from "@mshafiqyajid/react-tooltip";

function MyTooltip({ content, children }) {
  const { triggerProps, tooltipProps, placement, isVisible } = useTooltip({
    placement: "top",
    delay: 300,
  });

  return (
    <div style={{ position: "relative", display: "inline-flex" }}>
      <div {...triggerProps}>{children}</div>
      <div
        {...tooltipProps}
        data-placement={placement}
        style={{
          position: "absolute",
          bottom: "calc(100% + 8px)",
          left: "50%",
          translate: "-50% 0",
          opacity: isVisible ? 1 : 0,
          transition: "opacity 140ms ease",
          background: "#18181b",
          color: "#fff",
          padding: "4px 10px",
          borderRadius: "6px",
          fontSize: "0.78rem",
          whiteSpace: "nowrap",
          pointerEvents: "none",
        }}
      >
        {content}
      </div>
    </div>
  );
}

API #

PropTypeDefaultDescription
contentReactNodeTooltip text or JSX content
placementtop | bottom | left | right (each with optional -start / -end)"top"Preferred side and alignment
size"sm" | "md" | "lg""md"Size of the tooltip bubble
tone"neutral" | "primary" | "success" | "danger""neutral"Color tone
delaynumber0Show delay in ms (overridden by TooltipProvider)
multilinebooleanfalseAllow content to wrap
disabledbooleanfalseDisable the tooltip entirely
offsetnumber8Gap between trigger and tooltip in px
collisionPaddingnumber8Viewport edge margin for flip / shift
flipbooleantrueAuto-flip to opposite side near edges
shiftbooleantruePush back into view along the cross-axis
strategy"absolute" | "fixed""absolute"Positioning strategy
stickybooleanfalseKeep tooltip open while cursor is over it (deprecated alias for interactive)
interactivebooleanfalseKeep tooltip open while cursor is over the tooltip body; enables pointer-events inside the tooltip
followCursorbooleanfalseTooltip follows cursor position instead of anchoring to the trigger
headerReactNodeOptional content rendered above the main content
footerReactNodeOptional content rendered below the main content
longPressDelaynumber500Long-press delay in ms for touch trigger. Set 0 to disable touch
groupstringGroup key linking tooltips for ↓/↑ keyboard cycling
groupIdstringOptional id within the group for ordering (falls back to DOM order)
Edit this page on GitHub