AniUI

Popover

A popover that displays rich content in a floating panel triggered by a button press.

import { Text } from "react-native";
import {
  Popover,
  PopoverTrigger,
  PopoverContent,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";

export function MyScreen() {
  return (
    <Popover>
      <PopoverTrigger>
        <Button>Open Popover</Button>
      </PopoverTrigger>
      <PopoverContent>
        <Text className="text-sm text-card-foreground">
          This is the popover content. Place anything here.
        </Text>
      </PopoverContent>
    </Popover>
  );
}

Installation

npx @aniui/cli add popover

This component requires react-native-reanimated to be installed in your project.

Usage

app/index.tsx
import { Text } from "react-native";
import {
  Popover,
  PopoverTrigger,
  PopoverContent,
} from "@/components/ui/popover";
import { Button } from "@/components/ui/button";

export function MyScreen() {
  return (
    <Popover>
      <PopoverTrigger>
        <Button>Open Popover</Button>
      </PopoverTrigger>
      <PopoverContent>
        <Text className="text-sm text-card-foreground">
          This is the popover content. Place anything here.
        </Text>
      </PopoverContent>
    </Popover>
  );
}

Components

Popover is a compound component made up of several parts:

ComponentDescription
Popover

Root component that manages open/closed state. Supports both controlled and uncontrolled usage.

PopoverTrigger

The pressable element that toggles the popover.

PopoverContent

The floating panel that displays the popover content.

Props

Popover

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

Sub-components (PopoverTrigger, PopoverContent) accept className and their respective React Native base props.

Source

components/ui/popover.tsx
import React, { createContext, useContext, useState } from "react";
import { View, Pressable, Modal } from "react-native";
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
import { cn } from "@/lib/utils";

const PopoverCtx = createContext<{ open: boolean; toggle: () => void; close: () => void }>({ open: false, toggle: () => {}, close: () => {} });
export interface PopoverProps {
  open?: boolean;
  onOpenChange?: (open: boolean) => void;
  children: React.ReactNode;
}
export function Popover({ open: controlled, onOpenChange, children }: PopoverProps) {
  const [internal, setInternal] = useState(false);
  const isOpen = controlled ?? internal;
  const setOpen = (v: boolean) => { setInternal(v); onOpenChange?.(v); };
  return <PopoverCtx.Provider value={{ open: isOpen, toggle: () => setOpen(!isOpen), close: () => setOpen(false) }}>{children}</PopoverCtx.Provider>;
}
export interface PopoverTriggerProps extends React.ComponentPropsWithoutRef<typeof Pressable> {
  className?: string;
  children?: React.ReactNode;
}
export function PopoverTrigger({ className, children, ...props }: PopoverTriggerProps) {
  const { toggle } = useContext(PopoverCtx);
  return (
    <Pressable className={cn("min-h-12 min-w-12", className)} onPress={toggle} accessible={true} accessibilityRole="button" {...props}>
      {children}
    </Pressable>
  );
}
export interface PopoverContentProps extends React.ComponentPropsWithoutRef<typeof View> {
  className?: string;
  children?: React.ReactNode;
}
export function PopoverContent({ className, children, ...props }: PopoverContentProps) {
  const { open, close } = useContext(PopoverCtx);
  if (!open) return null;
  return (
    <Modal transparent animationType="none" onRequestClose={close}>
      <Pressable className="flex-1" onPress={close}>
        <Animated.View entering={FadeIn.duration(150)} exiting={FadeOut.duration(100)} className="flex-1 items-center justify-center">
          <Pressable onPress={(e) => e.stopPropagation()}>
            <View className={cn("w-72 rounded-lg border border-border bg-card p-4 shadow-lg", className)} {...props}>{children}</View>
          </Pressable>
        </Animated.View>
      </Pressable>
    </Modal>
  );
}