Toggletip

Extra information behind an info button that works on every input. A pointer that can hover gets it as a tooltip; a click or a tap pins it open; Escape or a tap outside closes it.

Monthly active users

Installation#

# One-time setup (tokens + lib helpers)npx koalaui-cli@latest init# Add this component (its dependencies come along)npx koalaui-cli@latest add toggletip

Usage#

usage.tsxTSX
import { Toggletip } from "@/components/ui/toggletip"export function Example() {  return <Toggletip content="People who opened the app in the last 30 days." />}

Anatomy#

import { Toggletip } from "@/components/ui/toggletip"<Toggletip content="..." /><Toggletip content="...">  <button /></Toggletip>

Tooltip or Toggletip#

Touch has no hover, so a Tooltip never opens from a tap. That is right for the name of an icon-only button, which already has an aria-label and whose tap runs it. It is wrong for help behind an info icon, which a touch user needs as much as anyone. That help is a Toggletip: its button does nothing but open it, so a tap can. Anything a person must read before acting goes on screen instead, and anything with buttons is a Popover.

Beside a field label#

info on a FieldLabel renders a small Toggletip right after the label, outside the <label> so it neither joins the label's name nor focuses the input. The same text still describes the input for screen readers.

Shown on invoices and receipts. You can change it later.
Retention

Custom trigger#

Sizes#

LabelSection title

Side#

toprightbottomleft

API reference#

Toggletip

An info button and the bubble it opens, built on Popover (Radix). The bubble looks like a Tooltip; unlike one, it opens on a tap, stays until dismissed and can hold one link. Accepts className, merged last onto the bubble.

PropTypeDefaultDescription
content*ReactNode-What the bubble says. One or two sentences and at most one link: anything with buttons or a form is a Popover.
childrenReactElement-A custom trigger, which must be a button (it receives the open state, aria-expanded and the handlers). Defaults to an info button.
labelstring"More information"Accessible name of the default info button. Name what it explains when there are several on screen.
variant"text" | "graph""text"text is the inverted chip of a text Tooltip; graph is the popover card, for a title plus a description.
size"sm" | "md""md"The default button's glyph: sm (14px) inline with a label, md (16px) beside a title. Either way the target reaches 40px; sm grows sideways so it never covers the control under a label.
side"top" | "right" | "bottom" | "left""top"Preferred side; it flips when there is no room.
align"start" | "center" | "end""center"Alignment against the trigger.
openboolean-Controlled open state.
defaultOpenbooleanfalseInitial open state when uncontrolled.
onOpenChange(open: boolean) => void-Called when it opens or closes.
triggerClassNamestring-Classes merged onto the default info button.
Data attributeDescription
data-stateopen or closed on the trigger and the bubble.
data-varianttext or graph on the bubble.
CSS variableDescription
--surfaceSet on the bubble to its own ground, as on Tooltip, so nested parts blend with it.

FAQ#

A tap on the info button opens the bubble and it stays until you tap outside, tap the button again or press Escape. Nothing else happens on that tap, which is why it may open: a tap never does two things.