Skip to content
v1.4.2
Fit

Tooltip

A small hover/focus hint that wraps a single trigger element. Four sides and an open delay. Keep the content to a short phrase — for richer, interactive content use Popover.

bash
jlds add tooltip

The bubble is rendered into <body> and anchored to the trigger by Anchored Popup, so it escapes any ancestor that would clip it, and flips to the opposite side when there isn't room. That primitive installs automatically as a registry dependency.

Usage

html
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/tooltip.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/css/button.css">
<!-- behavior layer: show on hover/focus -->
<script src="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/js/core.js" defer></script>
<script src="https://cdn.jsdelivr.net/gh/jarooda/jlds@main/registry/js/tooltip.js" defer></script>

<span class="jl-tooltip">
  <button class="jl-btn jl-btn--secondary jl-btn--md">Hover me</button>
  <span class="jl-tooltip__pop" role="tooltip" data-side="top">
    Saves automatically
    <span class="jl-tooltip__arrow"></span>
  </span>
</span>
vue
<script setup lang="ts">
import { Tooltip } from "@/components/ui/tooltip"
import { Button } from "@/components/ui/button"
</script>

<template>
  <Tooltip content="Saves automatically">
    <Button variant="secondary">Hover me</Button>
  </Tooltip>
</template>
tsx
import { Tooltip } from "@/components/ui/tooltip"
import { Button } from "@/components/ui/button"

<Tooltip content="Saves automatically">
  <Button variant="secondary">Hover me</Button>
</Tooltip>

Sides

top (default) · bottom · left · right

html
<span class="jl-tooltip">
  <button class="jl-btn jl-btn--secondary">Right</button>
  <span class="jl-tooltip__pop" role="tooltip" data-side="right">On the right<span class="jl-tooltip__arrow"></span></span>
</span>
vue
<template>
  <Tooltip content="On top" side="top"><Button>Top</Button></Tooltip>
  <Tooltip content="On the right" side="right"><Button>Right</Button></Tooltip>
  <Tooltip content="On bottom" side="bottom"><Button>Bottom</Button></Tooltip>
  <Tooltip content="On the left" side="left"><Button>Left</Button></Tooltip>
</template>
tsx
<Tooltip content="On top" side="top"><Button>Top</Button></Tooltip>
<Tooltip content="On the right" side="right"><Button>Right</Button></Tooltip>
<Tooltip content="On bottom" side="bottom"><Button>Bottom</Button></Tooltip>
<Tooltip content="On the left" side="left"><Button>Left</Button></Tooltip>

Props

PropTypeDefaultDescription
contentReact.ReactNodeTooltip text / content (Vue: prop or content slot)
side"top" | "bottom" | "left" | "right""top"Placement relative to the trigger
delaynumber120Open delay in ms
openbooleanControlled open state (Vue: v-model:open); omit for hover/focus
onOpenChange(open: boolean) => voidFires when the tip wants to open/close (Vue: update:open)
disabledbooleanfalseRender the trigger with no tooltip

In Vue, the trigger goes in the default slot; the tip content in the content slot (or the content prop). Drive it as a controlled overlay with v-model:open, or set disabled to render the trigger without any tooltip.

CSS classes (HTML)

ClassPurpose
.jl-tooltipWrapper around the trigger — always required
.jl-tooltip__pop + data-side="…"The hint bubble and its placement
.jl-tooltip__arrowThe little pointer

The behavior layer toggles data-show on hover/focus; positioning is pure CSS from data-side. Set data-delay on .jl-tooltip to change the open delay.