AniUI

Tooltip

A tooltip that displays informative text when users press and hold an element.

Web preview — components render natively on iOS & Android
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
import { Text } from "react-native";

export function MyScreen() {
  return (
    <Tooltip>
      <TooltipTrigger>
        <Text>Press and hold me</Text>
      </TooltipTrigger>
      <TooltipContent>This is a tooltip</TooltipContent>
    </Tooltip>
  );
}

Installation#

npx @aniui/cli add tooltip

This component requires @rn-primitives/tooltip, @rn-primitives/portal, and react-native-reanimated.

Usage#

app/index.tsx
import { Tooltip, TooltipTrigger, TooltipContent } from "@/components/ui/tooltip";
import { Text } from "react-native";

export function MyScreen() {
  return (
    <Tooltip>
      <TooltipTrigger>
        <Text>Press and hold me</Text>
      </TooltipTrigger>
      <TooltipContent>This is a tooltip</TooltipContent>
    </Tooltip>
  );
}

Tooltip Position#

Web preview — components render natively on iOS & Android
<Tooltip>
  <TooltipTrigger><Text>Top tooltip</Text></TooltipTrigger>
  <TooltipContent side="top">Tooltip above</TooltipContent>
</Tooltip>
<Tooltip>
  <TooltipTrigger><Text>Bottom tooltip</Text></TooltipTrigger>
  <TooltipContent side="bottom">Tooltip below</TooltipContent>
</Tooltip>

Props#

Tooltip#

PropTypeDefault
open
boolean
onOpenChange
(open: boolean) => void
children
React.ReactNode
required

TooltipTrigger#

PropTypeDefault
className
string
children
React.ReactNode

TooltipContent#

PropTypeDefault
children
React.ReactNode | string
required
side
"top" | "bottom" | "left" | "right"
"top"
sideOffset
number
8
className
string

Accessibility#

  • Uses @rn-primitives/tooltip for trigger-relative positioning
  • Collision detection prevents overflow
  • accessibilityRole="button" on trigger
  • Requires <PortalHost /> at app root

Source#

components/ui/tooltip.tsx
import React from "react";
import { View, Text, Pressable } from "react-native";
import * as TooltipPrimitive from "@rn-primitives/tooltip";
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
import { cn } from "@/lib/utils";

export interface TooltipProps {
  children: React.ReactNode;
  open?: boolean;
  onOpenChange?: (open: boolean) => void;
}

export function Tooltip({ children, open, onOpenChange }: TooltipProps) {
  return <TooltipPrimitive.Root open={open} onOpenChange={onOpenChange}>{children}</TooltipPrimitive.Root>;
}

export interface TooltipTriggerProps extends React.ComponentPropsWithoutRef<typeof Pressable> {
  className?: string;
  children?: React.ReactNode;
}

export function TooltipTrigger({ className, children, ...props }: TooltipTriggerProps) {
  return (
    <TooltipPrimitive.Trigger asChild>
      <Pressable className={cn("min-h-12 min-w-12", className)} accessible={true} accessibilityRole="button" {...props}>
        {children}
      </Pressable>
    </TooltipPrimitive.Trigger>
  );
}

export interface TooltipContentProps extends React.ComponentPropsWithoutRef<typeof View> {
  className?: string;
  children?: React.ReactNode;
  side?: "top" | "bottom" | "left" | "right";
  sideOffset?: number;
}

export function TooltipContent({ className, children, side = "top", sideOffset = 8, ...props }: TooltipContentProps) {
  return (
    <TooltipPrimitive.Portal>
      <TooltipPrimitive.Content side={side} sideOffset={sideOffset} avoidCollisions>
        <Animated.View entering={FadeIn.duration(150)} exiting={FadeOut.duration(100)}>
          <View className={cn("rounded-md bg-primary px-3 py-1.5", className)} {...props}>
            {typeof children === "string" ? (
              <Text className="text-xs text-primary-foreground text-center">{children}</Text>
            ) : children}
          </View>
        </Animated.View>
      </TooltipPrimitive.Content>
    </TooltipPrimitive.Portal>
  );
}