Tooltip

A hand-drawn Base UI tooltip styled with shadcn conventions. It portals its content, draws its own sketch outline, and can carry any paper texture.

Tooltip
Hand-drawn tooltips that follow their trigger on every side.
Sides
AlignmentRelative to the trigger edge
Paper textures
Icon trigger
Long textWraps at max-width

Installation

npx shadcn@latest add https://sketchcn.chuwii.com/r/tooltip.json

Styles

Tooltip leans on these rules from sketch.css. The shadcn CLI installs the file with sketch-provider; copying the component by hand means copying them too.

[data-paper]:not([data-paper="default"])::before,
[data-slot="card"][data-variant]:not([data-variant="default"])::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--paper-pattern);
  opacity: var(--paper-opacity, 0.4);
  mask-image: var(--paper-image);
  -webkit-mask-image: var(--paper-image);
  mask-repeat: repeat;
  -webkit-mask-repeat: repeat;
}

Read the whole file for the drawing variables, paper textures and reduced-motion rules.

Usage

import { Palette } from "@matita/icons/react";
import { Button } from "@/components/ui/button";
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip";

export function PaletteButton() {
  return (
    <TooltipProvider>
      <Tooltip>
        <TooltipTrigger
          render={
            <Button variant="outline" size="icon" aria-label="Palette">
              <Palette />
            </Button>
          }
        />
        <TooltipContent>Change the palette</TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
}

Props

TooltipProvider

PropTypeDefaultDescription
delaynumber200Milliseconds to wait before a tooltip opens on hover.

TooltipContent

PropTypeDefaultDescription
variantPaperVariant"polkadots"Paper texture drawn behind the content.

Positioning stays with Base UI. Only the defaults differ: side is "top", sideOffset is 8, align is "center".

Tooltip and TooltipTrigger add nothing; their props are forwarded to the matching Base UI primitives.

Examples

Setup

Render <TooltipProvider> once near the root of your app so every tooltip shares one open delay.

import { TooltipProvider } from "@/components/ui/tooltip";

export function App({ children }: { children: React.ReactNode }) {
  return <TooltipProvider>{children}</TooltipProvider>;
}

Icon button

import { Palette } from "@matita/icons/react";
import { Button } from "@/components/ui/button";
import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@/components/ui/tooltip";

export function PaletteButton() {
  return (
    <Tooltip>
      <TooltipTrigger
        render={
          <Button variant="outline" size="icon" aria-label="Palette">
            <Palette />
          </Button>
        }
      />
      <TooltipContent>Change the palette</TooltipContent>
    </Tooltip>
  );
}

Side and offset

<Tooltip>
  <TooltipTrigger render={<Button variant="outline">Layers</Button>} />
  <TooltipContent side="right" sideOffset={12}>
    Show the layer panel
  </TooltipContent>
</Tooltip>

Paper texture

<Tooltip>
  <TooltipTrigger render={<Button variant="outline">Grid</Button>} />
  <TooltipContent variant="graph">Snap strokes to the grid</TooltipContent>
</Tooltip>

No delay

<TooltipProvider delay={0}>
  <Tooltip>
    <TooltipTrigger render={<Button variant="outline">Instant</Button>} />
    <TooltipContent>Opens with no delay</TooltipContent>
  </Tooltip>
</TooltipProvider>