Popover
tetra-ui/popoverFreeComponent
Displays content in a portal relative to the triggering button element.
Live preview
live · rendered by the registry
Rendered by tetra-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://tetra-ui.com/r/popover.jsonSource
1import {2 createContext,3 useCallback,4 useContext,5 useEffect,6 useMemo,7 useRef,8 useState,9} from "react";10import {11 BackHandler,12 type DimensionValue,13 type GestureResponderEvent,14 type LayoutChangeEvent,15 type LayoutRectangle,16 Pressable,17 useWindowDimensions,18 type View,19 type ViewStyle,20} from "react-native";21import Animated, {22 Easing,23 Extrapolation,24 interpolate,25 type SharedValue,26 useAnimatedStyle,27 useSharedValue,28 withTiming,29} from "react-native-reanimated";30import { useSafeAreaInsets } from "react-native-safe-area-context";31import { useUniwind } from "uniwind";32import { useRelativePosition } from "@/hooks/use-relative-position";33import { cn, mergeRefs } from "@/lib/utils";34import { Portal, PortalOverlay } from "./portal";35import { Slot } from "./slot";3637// Constants38const ANIMATION_DURATION = 200;39const ANIMATION_EASING = Easing.out(Easing.cubic);40const SCREEN_MARGIN = 12;41const FIT_MAX_WIDTH = 280;42const OVERLAY_OPACITY = { dark: 0.32, light: 0.12 } as const;43const AnimatedPressable = Animated.createAnimatedComponent(Pressable);4445// Types46type LayoutPosition = {47 pageX: number;48 pageY: number;49 width: number;50 height: number;51};5253type PopoverSide = "top" | "bottom" | "left" | "right";54type PopoverAlign = "start" | "center" | "end";5556type PopoverContextProps = {57 open: boolean;58 onOpenChange: (open: boolean) => void;59 visibilityProgress: SharedValue<number>;60 triggerPosition?: LayoutPosition;61 setTriggerPosition: (position?: LayoutPosition) => void;62 contentLayout?: LayoutRectangle;63 setContentLayout: (position?: LayoutRectangle) => void;64};6566type PopoverProps = Partial<PopoverContextProps> & {67 children: React.ReactNode;68};6970type PopoverPortalProps = Partial<React.ComponentProps<typeof Portal>>;7172type PopoverOverlayProps = {73 closeOnPress?: boolean;74 className?: string;75};7677type PopoverContentProps = React.ComponentProps<typeof View> & {78 avoidCollisions?: boolean;79 side?: PopoverSide;80 sideOffset?: number;81 align?: PopoverAlign;82 alignOffset?: number;83 width?: "full" | "fit" | "auto" | "trigger" | number | `${number}%`;84};8586type PopoverTriggerProps = React.ComponentPropsWithRef<typeof Pressable> & {87 asChild?: boolean;88};8990type PopoverCloseProps = React.ComponentPropsWithRef<typeof Pressable> & {91 asChild?: boolean;92};9394// Context95const PopoverContext = createContext<PopoverContextProps | null>(null);9697export const usePopover = () => {98 const context = useContext(PopoverContext);99// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from tetra-ui
All 41 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Accordionaccordion | tetra-ui | Components | Free | 1 dep | |
| Action Inputaction-input | tetra-ui | Components | Free | no deps | |
| Alertalert | tetra-ui | Components | Free | no deps | |
| Avataravatar | tetra-ui | Components | Free | no deps | |
| Badgebadge | tetra-ui | Components | Free | no deps | |
| Bottom Sheetbottom-sheet | tetra-ui | Components | Free | 4 deps · 7 files | |
| Buttonbutton | tetra-ui | Components | Free | no deps | |
| Cardcard | tetra-ui | Components | Free | no deps |
