Popover

Displays a floating content panel anchored to a trigger element with placement and alignment options.

Import

import { Popover } from 'heroui-native';

Anatomy

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content>
      <Popover.Arrow />
      <Popover.Close />
      <Popover.Title>...</Popover.Title>
      <Popover.Description>...</Popover.Description>
    </Popover.Content>
  </Popover.Portal>
</Popover>
  • Popover: Main container that manages open/close state, positioning, and provides context to child components.
  • Popover.Trigger: Clickable element that toggles popover visibility. Wraps any child element with press handlers.
  • Popover.Portal: Renders popover content in a portal layer above other content. Ensures proper stacking and positioning.
  • Popover.Overlay: Optional background overlay. Can be transparent or semi-transparent to capture outside clicks.
  • Popover.Content: Container for popover content with positioning, styling, and collision detection. Supports both popover and bottom-sheet presentations.
  • Popover.Arrow: Optional arrow element pointing to the trigger. Automatically positioned based on placement.
  • Popover.Close: Close button that dismisses the popover when pressed. Renders a default X icon if no children provided.
  • Popover.Title: Optional title text with pre-styled typography.
  • Popover.Description: Optional description text with muted styling.

Usage

Basic Usage

The Popover component uses compound parts to create floating content panels.

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content>...</Popover.Content>
  </Popover.Portal>
</Popover>

With Title and Description

Structure popover content with title and description for better information hierarchy.

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content>
      <Popover.Close />
      <Popover.Title>...</Popover.Title>
      <Popover.Description>...</Popover.Description>
    </Popover.Content>
  </Popover.Portal>
</Popover>

With Arrow

Add an arrow pointing to the trigger element for better visual connection.

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content placement="top">
      <Popover.Arrow />
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>

Width Control

Control the width of the popover content using the width prop.

{
  /* Fixed width in pixels */
}
<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content width={320}>...</Popover.Content>
  </Popover.Portal>
</Popover>;

{
  /* Match trigger width */
}
<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content width="trigger">...</Popover.Content>
  </Popover.Portal>
</Popover>;

{
  /* Full width (100%) */
}
<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content width="full">...</Popover.Content>
  </Popover.Portal>
</Popover>;

{
  /* Auto-size to content (default) */
}
<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content width="content-fit">...</Popover.Content>
  </Popover.Portal>
</Popover>;

Bottom Sheet Presentation

Use bottom sheet presentation for mobile-optimized interaction patterns.

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content presentation="bottom-sheet">
      <Popover.Title>...</Popover.Title>
      <Popover.Description>...</Popover.Description>
      <Popover.Close asChild>
        <Button>Close</Button>
      </Popover.Close>
    </Popover.Content>
  </Popover.Portal>
</Popover>

Placement Options

Control where the popover appears relative to the trigger element.

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Content placement="left">...</Popover.Content>
  </Popover.Portal>
</Popover>

Alignment Options

Fine-tune content alignment along the placement axis.

<Popover>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Content placement="top" align="start">
      ...
    </Popover.Content>
  </Popover.Portal>
</Popover>

Custom Animation

Configure custom animations for open and close transitions using the animation prop on Popover.Root.

<Popover
  animation={{
    entering: {
      type: 'spring',
      config: { damping: 15, stiffness: 300 },
    },
    exiting: {
      type: 'timing',
      config: { duration: 200 },
    },
  }}
>
  <Popover.Trigger>...</Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content>...</Popover.Content>
  </Popover.Portal>
</Popover>

Programmatic control

// Open or close popover programmatically using ref
const popoverRef = useRef<PopoverTriggerRef>(null);

// Open programmatically
popoverRef.current?.open();

// Close programmatically
popoverRef.current?.close();

// Full example
<Popover>
  <Popover.Trigger ref={popoverRef} asChild>
    <Button>Trigger</Button>
  </Popover.Trigger>
  <Popover.Portal>
    <Popover.Overlay />
    <Popover.Content>
      <Text>Content</Text>
      <Button onPress={() => popoverRef.current?.close()}>Close</Button>
    </Popover.Content>
  </Popover.Portal>
</Popover>;

Example

import { Ionicons } from '@expo/vector-icons';
import { Button, Popover, useThemeColor } from 'heroui-native';
import { Text, View } from 'react-native';

export default function PopoverExample() {
  const themeColorMuted = useThemeColor('muted');

  return (
    <Popover>
      <Popover.Trigger asChild>
        <Button variant="tertiary" size="sm">
          <Button.StartContent>
            <Ionicons
              name="information-circle"
              size={20}
              color={themeColorMuted}
            />
          </Button.StartContent>
          <Button.LabelContent>Show Info</Button.LabelContent>
        </Button>
      </Popover.Trigger>
      <Popover.Portal>
        <Popover.Overlay />
        <Popover.Content width={320} className="gap-1 rounded-xl px-6 py-4">
          <Popover.Close className="absolute top-3 right-3 z-50" />
          <Popover.Title>Information</Popover.Title>
          <Popover.Description>
            This popover includes a title and description to provide more
            structured information to users.
          </Popover.Description>
        </Popover.Content>
      </Popover.Portal>
    </Popover>
  );
}

API Reference

Popover

proptypedefaultdescription
childrenReactNode-Children elements to be rendered inside the popover
isOpenboolean-Whether the popover is open (controlled mode)
isDefaultOpenboolean-The open state of the popover when initially rendered (uncontrolled mode)
onOpenChange(isOpen: boolean) => void-Callback when the popover open state changes
closeDelaynumber400Delay in milliseconds before closing the popover
animationPopoverRootAnimation-Animation configuration
asChildbooleanfalseWhether to render as a child element
...ViewPropsViewProps-All standard React Native View props are supported

PopoverRootAnimation

Animation configuration for popover root component. Can be:

  • false or "disabled": Disable only root animations
  • "disable-all": Disable all animations including children
  • true or undefined: Use default animations
  • object: Custom animation configuration
proptypedefaultdescription
entering.valueSpringAnimationConfig | TimingAnimationConfig{ type: 'timing',
config: { duration: 200,
easing: Easing.out(Easing.ease) } }
Animation configuration for opening
exiting.valueSpringAnimationConfig | TimingAnimationConfig{ type: 'timing',
config: { duration: 150,
easing: Easing.bezier(0.4, 0, 1, 1) } }
Animation configuration for closing

SpringAnimationConfig

proptypedefaultdescription
type'spring'-Animation type (must be 'spring')
configWithSpringConfig-Reanimated spring animation configuration

TimingAnimationConfig

proptypedefaultdescription
type'timing'-Animation type (must be 'timing')
configWithTimingConfig-Reanimated timing animation configuration

Popover.Trigger

proptypedefaultdescription
childrenReactNode-The trigger element content
classNamestring-Additional CSS classes for the trigger
asChildbooleantrueWhether to render as a child element
...PressablePropsPressableProps-All standard React Native Pressable props are supported

Popover.Portal

proptypedefaultdescription
childrenReactNode-The portal content (required)
hostNamestring-Optional name of the host element for the portal
forceMountboolean-Whether to force mount the component in the DOM
classNamestring-Additional CSS classes for the portal container
...ViewPropsViewProps-All standard React Native View props are supported

Popover.Overlay

proptypedefaultdescription
classNamestring-Additional CSS classes for the overlay
closeOnPressbooleantrueWhether to close the popover when overlay is pressed
forceMountboolean-Whether to force mount the component in the DOM
animationPopoverOverlayAnimation-Animation configuration
asChildbooleanfalseWhether to render as a child element
...Animated.ViewPropsAnimated.ViewProps-All Reanimated Animated.View props are supported

PopoverOverlayAnimation

Animation configuration for popover overlay component. Can be:

  • false or "disabled": Disable all animations
  • true or undefined: Use default animations
  • object: Custom animation configuration
proptypedefaultdescription
opacity.value[number, number, number][0, 1, 0]Opacity values [idle, open, close]

Popover.Content (Popover Presentation)

proptypedefaultdescription
childrenReactNode-The popover content
widthnumber | 'trigger' | 'content-fit' | 'full''content-fit'Width sizing strategy for the content
placement'top' | 'bottom' | 'left' | 'right''bottom'Placement of the popover relative to trigger
align'start' | 'center' | 'end''center'Alignment along the placement axis
avoidCollisionsbooleantrueWhether to flip placement when close to viewport edges
offsetnumber8Distance from trigger element in pixels
alignOffsetnumber0Offset along the alignment axis in pixels
disablePositioningStylebooleanfalseWhether to disable automatic positioning styles
forceMountboolean-Whether to force mount the component in the DOM
insetsInsets-Screen edge insets to respect when positioning
classNamestring-Additional CSS classes for the content container
presentation'popover'-Presentation mode for the popover
animationPopupPopoverContentAnimation-Animation configuration
asChildbooleanfalseWhether to render as a child element
...Animated.ViewPropsAnimated.ViewProps-All Reanimated Animated.View props are supported

Popover.Content (Bottom Sheet Presentation)

proptypedefaultdescription
childrenReactNode-The bottom sheet content
presentation'bottom-sheet'-Presentation mode for the popover
bottomSheetViewClassNamestring-Additional CSS classes for the bottom sheet view
bottomSheetViewPropsBottomSheetViewProps-Props for the bottom sheet view
enablePanDownToClosebooleantrueWhether pan down gesture closes the sheet
backgroundStyleViewStyle-Style for the bottom sheet background
handleIndicatorStyleViewStyle-Style for the bottom sheet handle indicator
...BottomSheetPropsBottomSheetProps-All @gorhom/bottom-sheet props are supported

PopupPopoverContentAnimation

Animation configuration for popover content component (popover presentation). Can be:

  • false or "disabled": Disable all animations
  • true or undefined: Use default animations
  • object: Custom animation configuration
proptypedefaultdescription
opacity.value[number, number, number][0, 1, 0]Opacity values [idle, open, close]
scale.value[number, number, number][0.95, 1, 0.95]Scale values [idle, open, close]
translateX.value[number, number, number]Based on placement
(4, 0, 4) or (-4, 0, -4)
TranslateX values [idle, open, close]
translateY.value[number, number, number]Based on placement
(4, 0, 4) or (-4, 0, -4)
TranslateY values [idle, open, close]
transformOrigin.valuestringBased on placement
'top', 'bottom', 'left', 'right'
Transform origin value

Popover.Arrow

proptypedefaultdescription
classNamestring-Additional CSS classes for the arrow
heightnumber8Height of the arrow in pixels
widthnumber16Width of the arrow in pixels
fillstring-Fill color of the arrow (defaults to content background)
strokestring-Stroke (border) color of the arrow (defaults to content border color)
strokeWidthnumber1Stroke width of the arrow border in pixels
strokeBaselineInsetnumber1Baseline inset in pixels for stroke alignment
placement'top' | 'bottom' | 'left' | 'right'-Placement of the popover (inherited from content)
childrenReactNode-Custom arrow content (replaces default SVG arrow)
styleStyleProp<ViewStyle>-Additional styles for the arrow container
...ViewPropsViewProps-All standard React Native View props are supported

Popover.Close

proptypedefaultdescription
childrenReactNode-The close button content
classNamestring-Additional CSS classes for the close button
iconPropsPopoverCloseIconProps-Close icon configuration
hitSlopnumber | Insets12Additional touch area around the button
asChildboolean-Whether to render as a child element
...PressablePropsPressableProps-All standard React Native Pressable props are supported

PopoverCloseIconProps

proptypedefaultdescription
sizenumber18Size of the icon
colorstring--colors.mutedColor of the icon

Popover.Title

proptypedefaultdescription
childrenReactNode-The title text content
classNamestring-Additional CSS classes for the title
...TextPropsTextProps-All standard React Native Text props are supported

Popover.Description

proptypedefaultdescription
childrenReactNode-The description text content
classNamestring-Additional CSS classes for the description
...TextPropsTextProps-All standard React Native Text props are supported

Hooks

usePopover

Hook to access popover context values within custom components or compound components.

import { usePopover } from 'heroui-native';

const CustomContent = () => {
  const { isOpen, onOpenChange, triggerPosition } = usePopover();
  // ... your implementation
};

Returns: UsePopoverReturn

propertytypedescription
isOpenbooleanWhether the popover is currently open
onOpenChange(open: boolean) => voidCallback function to change the popover open state
isDefaultOpenboolean | undefinedWhether the popover should be open by default (uncontrolled mode)
isDisabledboolean | undefinedWhether the popover is disabled
triggerPositionLayoutPosition | nullThe position of the trigger element relative to the viewport
setTriggerPosition(triggerPosition: LayoutPosition | null) => voidFunction to update the trigger element's position
contentLayoutLayoutRectangle | nullThe layout measurements of the popover content
setContentLayout(contentLayout: LayoutRectangle | null) => voidFunction to update the content layout measurements
nativeIDstringUnique identifier for the popover instance
closeDelaynumber | undefinedDelay in milliseconds before the popover closes

Note: This hook must be used within a Popover component. It will throw an error if called outside of the popover context.

usePopoverAnimation

Hook to access popover animation state values within custom components or compound components.

import { usePopoverAnimation } from 'heroui-native';

const CustomContent = () => {
  const { popoverState, progress, isDragging } = usePopoverAnimation();
  // ... your implementation
};

Returns: UsePopoverAnimationReturn

propertytypedescription
popoverState'idle' | 'open' | 'close'Extended internal state for coordinating animations
progressSharedValue<number>Progress value for the popover animation (0=idle, 1=open, 2=close)
isDraggingSharedValue<boolean>Dragging state shared value

Note: This hook must be used within a Popover component. It will throw an error if called outside of the popover animation context.

On this page