Popover
A floating overlay anchored to a trigger element, used for contextual content and forms.
The Popover component is a floating overlay that appears below (or near) a trigger element. It supports configurable alignment, side offset, controlled/uncontrolled state, and auto-positioning to stay within screen bounds. Built with React Native's Modal API and a compound component pattern.
Preview
Installation
npx novaui-cli add popoverImport
import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverAnchor,
PopoverHeader,
PopoverTitle,
PopoverDescription,
} from 'novaui-components'Basic Usage
The Popover is a compound component with these parts:
Popover- Root container with open/close state and position trackingPopoverTrigger- The element that toggles the popover on pressPopoverContent- The floating content panelPopoverAnchor- Optional custom anchor element for positioningPopoverHeader- Groups the title and descriptionPopoverTitle- The popover headingPopoverDescription- Subtitle or description text
import {
Popover,
PopoverTrigger,
PopoverContent,
PopoverHeader,
PopoverTitle,
PopoverDescription,
} from 'novaui-components'
import { Button } from 'novaui-components'
import { View, Text, TextInput } from 'react-native'
export function BasicPopover() {
return (
<Popover>
<PopoverTrigger>
<Button variant="outline" label="Open Popover" />
</PopoverTrigger>
<PopoverContent>
<PopoverHeader>
<PopoverTitle>Dimensions</PopoverTitle>
<PopoverDescription>Set the dimensions for the layer.</PopoverDescription>
</PopoverHeader>
<View className="gap-2">
<View className="flex-row items-center justify-between">
<Text className="text-sm">Width</Text>
<TextInput
className="h-8 w-20 rounded-md border border-input bg-background px-2"
defaultValue="100%"
/>
</View>
<View className="flex-row items-center justify-between">
<Text className="text-sm">Max. width</Text>
<TextInput
className="h-8 w-20 rounded-md border border-input bg-background px-2"
defaultValue="300px"
/>
</View>
</View>
</PopoverContent>
</Popover>
)
}Alignment
Control how the popover aligns relative to the trigger:
// Start-aligned (left edge of trigger)
<PopoverContent align="start">...</PopoverContent>
// Center-aligned (default)
<PopoverContent align="center">...</PopoverContent>
// End-aligned (right edge of trigger)
<PopoverContent align="end">...</PopoverContent>Controlled State
Control the popover programmatically:
import { useState } from 'react'
export function ControlledPopover() {
const [open, setOpen] = useState(false)
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger>
<Button variant="outline" label="Toggle" />
</PopoverTrigger>
<PopoverContent>
<PopoverHeader>
<PopoverTitle>Controlled</PopoverTitle>
<PopoverDescription>
This popover is controlled externally.
</PopoverDescription>
</PopoverHeader>
</PopoverContent>
</Popover>
)
}Props API
Popover Props
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | - | Controlled open state |
onOpenChange | (open: boolean) => void | - | Callback when open state changes |
defaultOpen | boolean | false | Initial open state (uncontrolled) |
PopoverTrigger Props
Extends React.ComponentPropsWithoutRef<typeof Pressable>:
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Render as the child element instead of a Pressable |
PopoverContent Props
Extends React.ComponentPropsWithoutRef<typeof View>:
| Prop | Type | Default | Description |
|---|---|---|---|
align | 'start' | 'center' | 'end' | 'center' | Horizontal alignment relative to the trigger |
sideOffset | number | 4 | Distance in pixels between the trigger and content |
className | string | - | Additional CSS classes |
PopoverAnchor Props
Extends React.ComponentPropsWithoutRef<typeof View>:
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
PopoverHeader Props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
PopoverTitle Props
Extends React.ComponentPropsWithoutRef<typeof Text>:
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
PopoverDescription Props
Extends React.ComponentPropsWithoutRef<typeof Text>:
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes |
Positioning
The Popover automatically positions itself:
- Measures the trigger element's position on screen using
measure() - Places content below the trigger with the configured
sideOffset - Adjusts horizontal position based on
alignprop - Clamps to screen bounds so content doesn't overflow off-screen
Best Practices
-
Keep content concise: Popovers should contain small forms, settings, or quick info — not full pages
-
Use appropriate alignment: Align to the trigger edge that makes sense for the content layout
-
Dismiss on outside press: The built-in backdrop press handles this automatically
-
Don't overuse: Reserve popovers for contextual actions — use
Dialogfor focused tasks -
Width control: Default width is
w-72— override withclassNamefor wider or narrower content
Related Components
- Use
HoverCardfor preview content that appears on hover/press - Use
Dialogfor larger, centered modal content - Use
Tooltipfor simple text hints (if available)