Lattice components

Tooltip

Hover- and focus-triggered surface primitive that owns open delay, popper positioning, portal layering, and presence motion while you own the content.

@lattice-ui/tooltip Stable direction import Tooltip depends on core , layer , motion , popper

Tooltip is the primitive for a small, transient surface that explains a control: button hints, icon labels, and stat breakdowns. It opens on hover or selection after a delay, positions itself against the trigger with popper, and animates in and out — so your component only renders the label.

Reach for Tooltip when a surface should appear on hover or focus, wait a beat before showing (and skip that wait when moving between nearby triggers), anchor to its trigger with collision-aware placement, and dismiss when the pointer or selection leaves.

Import

import { Tooltip } from "@lattice-ui/tooltip";

Anatomy

Root, Trigger, Portal, and Content form the working tooltip. Wrap a region (or your whole app) in Provider to share open-delay behavior across many tooltips.

Tooltip anatomy
<Tooltip.Provider>
<Tooltip.Root>
<Tooltip.Trigger />
<Tooltip.Portal>
<Tooltip.Content />
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
PartRequiredResponsibility
Tooltip.ProvidernoShares delay defaults and the skip-delay grace window across the tooltips inside it.
Tooltip.RootyesOwns open state and the delayed-open / close logic; shares trigger and content refs.
Tooltip.TriggeryesThe element whose hover/selection opens and closes the tooltip; the popper anchor.
Tooltip.PortalyesRenders the content into a ScreenGui outside the local tree.
Tooltip.ContentyesThe popper-positioned, motion-driven, dismissable surface.

Example

A provider wrapping a tooltip with a custom trigger and an app-owned label surface.

StatTooltip.tsx
import { Tooltip } from "@lattice-ui/tooltip";
export function StatTooltip() {
return (
<Tooltip.Provider delayDuration={500}>
<Tooltip.Root>
<Tooltip.Trigger asChild>
<textbutton Text="ATK 142" Size={UDim2.fromOffset(96, 32)} />
</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content placement="top" sideOffset={8}>
<frame
BackgroundColor3={Color3.fromRGB(24, 26, 32)}
Size={UDim2.fromOffset(200, 56)}
>
<uicorner CornerRadius={new UDim(0, 8)} />
<textlabel
BackgroundTransparency={1}
Size={UDim2.fromScale(1, 1)}
Text="Base 120 + 22 from gear"
TextColor3={Color3.fromRGB(240, 244, 250)}
/>
</frame>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Provider>
);
}

How it behaves

Open behavior

Tooltip.Trigger tracks two activity sources — hover (MouseEnter/MouseLeave) and focus (SelectionGained/SelectionLost). The tooltip opens when either becomes active and closes when both are inactive. Hover opens go through the delay; focus opens are immediate, which suits gamepad and keyboard selection. A disabled trigger never opens and closes immediately if it loses activity.

Open delay and skip window

Hover opens wait for a delay before showing. The delay resolves from Root’s delayDuration, then the Provider’s delayDuration (default 700 ms). When a tooltip was opened recently — within the provider’s skipDelayDuration (default 300 ms) — the next hover open is shortened to at most that skip window, so moving between adjacent triggers feels instant instead of re-waiting the full delay. Leaving a trigger cancels any pending open.

Positioning

Tooltip.Content positions itself with popper, anchored to the trigger. Set placement for the preferred side, sideOffset for the gap from the trigger, alignOffset to shift along the side, and collisionPadding to keep the content inside the viewport. The content is hidden off-screen until popper has measured and positioned it, so it never flashes in the wrong spot.

Layering

Tooltip.Portal renders the content into a ScreenGui outside the local component tree. By default it inherits the surrounding portal container and display order; pass container to target a specific PlayerGui and displayOrderBase to order it against other layered surfaces.

Dismissal

Tooltip.Content runs as a non-modal dismissable layer: it does not block interaction behind it, and an outside interaction closes it. Use onPointerDownOutside and onInteractOutside to observe those interactions before the tooltip closes.

Motion and presence

Tooltip.Content runs a default canvas-group popper entrance/exit recipe keyed to the resolved placement, so it animates from the trigger’s side without setup. Override it with transition, and pass forceMount to keep the content mounted through its exit animation (useful when you drive motion yourself or need the node to persist).

API reference

Tooltip.Provider

Prop Type Description
delayDuration number Default hover-open delay in milliseconds for tooltips inside this provider. Defaults to 700.
skipDelayDuration number Grace window in milliseconds during which a subsequent hover open is shortened. Defaults to 300.
children React.ReactNode The tooltips that share these delay defaults.

Tooltip.Root

Prop Type Description
open boolean Controlled open state. Pair with onOpenChange.
defaultOpen boolean Initial open state for uncontrolled usage. Defaults to false.
delayDuration number Overrides the provider's hover-open delay for this tooltip, in milliseconds.
onOpenChange (open: boolean) => void Called whenever the open state changes.
children React.ReactNode The trigger, portal, and content parts.

Tooltip.Trigger

Prop Type Description
disabled boolean Prevents the trigger from opening the tooltip and removes it from selection. Defaults to false.
asChild boolean Merge the trigger behavior and anchor ref onto the single child element instead of the default textbutton.
children React.ReactElement The element to render. Required when asChild is set.

Tooltip.Portal

Prop Type Description
container BasePlayerGui Target PlayerGui to render the content into. Defaults to the surrounding portal container.
displayOrderBase number Base DisplayOrder for the generated ScreenGui, used to order it against other layers.
children React.ReactNode The content part.

Tooltip.Content

Prop Type Description
placement PopperPlacement Preferred side/alignment of the content relative to the trigger.
sideOffset number Gap between the content and the trigger along the placement side.
alignOffset number Shift of the content along the placement axis.
collisionPadding number Minimum padding kept between the content and the viewport edges.
transition MotionConfig Overrides the default canvas-group popper entrance/exit recipe.
forceMount boolean Keeps the content mounted while exit motion runs.
onPointerDownOutside (event: LayerInteractEvent) => void Called when a pointer press occurs outside the content, before dismissal.
onInteractOutside (event: LayerInteractEvent) => void Called for any other outside interaction, before dismissal.
asChild boolean Render the single child element inside the positioned surface instead of arbitrary children.
children React.ReactNode The tooltip contents.