Tooltip
A short description shown on hover or keyboard focus.
- Chromium
- Firefox
- WebKit
- WCAG 2.2 AA
Preview
import { Button } from "@moe-ui/registry/components/ui/button";
import { Text } from "@moe-ui/registry/components/ui/text";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@moe-ui/registry/components/ui/tooltip";
export default function TooltipPreview() {
return (
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline">
<Text>Hover</Text>
</Button>
</TooltipTrigger>
<TooltipContent>
<Text>Add to library</Text>
</TooltipContent>
</Tooltip>
);
}
One command, your source
Installation
pnpm dlx @moe-ui/cli@beta add tooltipUsage
The CLI installs editable source into your application. Import the component from your configured UI directory:
import { Tooltip } from "@/components/ui/tooltip";Variants and composition
Compound parts and variants remain regular source in your project, so you can change them without wrapping a package API.
Public API
The canonical source panel below lists every public export, dependency, and the complete implementation shipped by the registry.
Keyboard and accessibility
The trigger is keyboard reachable, Escape dismisses the surface, and focus returns to the trigger. Modal surfaces keep focus within the active layer.
Browser support
This beta is release-tested in Chromium, Firefox, and WebKit in light and dark themes. See the web compatibility matrix for the current gate.
Nothing hiddenCanonical source and public exports3 exports
TooltipTooltipContentTooltipTrigger"use client";
import { NativeOnlyAnimatedView } from "./native-only-animated-view";
import { TextClassContext } from "./text";
import { cn } from "../../lib/utils";
import * as TooltipPrimitive from "@rn-primitives/tooltip";
import * as React from "react";
import { Platform, StyleSheet } from "react-native";
import { FadeInDown, FadeInUp, FadeOut } from "react-native-reanimated";
import { FullWindowOverlay as RNFullWindowOverlay } from "react-native-screens";
const Tooltip = TooltipPrimitive.Root;
const TooltipTrigger = TooltipPrimitive.Trigger;
const FullWindowOverlay =
Platform.OS === "ios" ? RNFullWindowOverlay : React.Fragment;
function TooltipContent({
className,
sideOffset = 4,
portalHost,
side = "top",
...props
}: TooltipPrimitive.ContentProps &
React.RefAttributes<TooltipPrimitive.ContentRef> & {
portalHost?: string;
}) {
return (
<TooltipPrimitive.Portal hostName={portalHost}>
<FullWindowOverlay>
<TooltipPrimitive.Overlay
style={Platform.select({ native: StyleSheet.absoluteFill })}
>
<NativeOnlyAnimatedView
entering={
side === "top"
? FadeInDown.withInitialValues({
transform: [{ translateY: 3 }],
}).duration(150)
: FadeInUp.withInitialValues({
transform: [{ translateY: -5 }],
})
}
exiting={FadeOut}
>
<TextClassContext.Provider value="text-xs text-primary-foreground">
<TooltipPrimitive.Content
sideOffset={sideOffset}
className={cn(
"bg-primary z-50 rounded-md px-3 py-2 sm:py-1.5",
Platform.select({
web: cn(
"animate-in fade-in-0 zoom-in-95 origin-[var(--radix-tooltip-content-transform-origin)] w-fit text-balance",
side === "bottom" && "slide-in-from-top-2",
side === "left" && "slide-in-from-right-2",
side === "right" && "slide-in-from-left-2",
side === "top" && "slide-in-from-bottom-2",
),
}),
className,
)}
side={side}
{...props}
/>
</TextClassContext.Provider>
</NativeOnlyAnimatedView>
</TooltipPrimitive.Overlay>
</FullWindowOverlay>
</TooltipPrimitive.Portal>
);
}
export { Tooltip, TooltipContent, TooltipTrigger };