Popover
Free · MITReact Native · ExpoA bubble anchored to an element whose arrow always points at the anchor's center, even when the bubble is pushed in from the screen edge; it flips above or below to fit and unfurls out of the arrow tip.
Installation
$ npx shadcn@latest add https://goodui.dev/native/r/popover.jsonThen run npx expo install --fix so react-native-reanimated, react-native-svg match your Expo SDK. Files land in components/goodui-native/popover.
- Wrap the app in ThemeProvider (the bubble renders in its overlay layer).
Usage
import { Popover } from "@/components/goodui-native/popover/popover";
<Popover
variant="tooltip"
placement="top"
accessibilityLabel="About billing"
content="Billed once a year. Cancel anytime."
>
<InfoIcon color={colors.textSecondary} />
</Popover>When to use
- A short explanation next to what it explains: an info icon, a chart value, a new feature.
- A small piece of UI tied to a control, such as a guest count picker under a field.
- A list of actions on an element: use context-menu (or action-sheet for screen-level choices).
- Content longer than a few lines or with several inputs: use bottom-sheet.
- Confirmations: use alert-dialog.
Examples
Content with its own controls
<Popover
title="Guests"
align="start"
accessibilityLabel={`Guests, ${guests}`}
content={(close) => (
<View style={{ gap: 12, width: 240 }}>
<GuestStepper value={guests} onChange={setGuests} />
<Button size="sm" onPress={close}>Done</Button>
</View>
)}
>
<GuestField count={guests} />
</Popover>Controlled coach mark
<Popover open={showTip} onOpenChange={setShowTip} title="Split the bill" content="Split any payment with the people in this chat.">
<SplitChip />
</Popover>API reference
| Prop | Type | Default |
|---|---|---|
| children* The anchor. Popover makes it the button that opens the bubble, so pass plain content (icon, text, chip), not another button. | ReactNode | — |
| content* Bubble content. A string renders as text; a function receives `close`. | ReactNode | ((close: () => void) => ReactNode) | — |
| title Heading inside a popover bubble. | string | — |
| open Whether the bubble is shown (controlled). | boolean | — |
| defaultOpen Open on first render when uncontrolled. | boolean | false |
| onOpenChange Called when the bubble opens or closes. | (open: boolean) => void | — |
| variant `popover` is a raised card for content and actions; `tooltip` is a small inverted label that also opens while the anchor is held (native) or hovered (web). | "popover" | "tooltip" | "popover" |
| placement Preferred side. It flips to the other side when the bubble does not fit. | "top" | "bottom" | "bottom" |
| align Horizontal alignment with the anchor before it is clamped to the screen. | "center" | "start" | "end" | "center" |
| maxWidth Maximum bubble width in points. Default 300 for popovers, 240 for tooltips. | number | — |
| haptic Haptic when a held tooltip appears. Default `true`. | boolean | true |
| accessibilityLabel Label for the anchor button. Defaults to the anchor's text. | string | — |
| anchorStyle Style of the anchor wrapper. | StyleProp<ViewStyle> | — |
| labels Overrides for the built-in strings; a GooduiLocaleProvider pack sets them app-wide. | Partial<PopoverLabels> | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- Open: the bubble grows out of the arrow tip; its height leads on the bouncy spring and its width follows on the morph spring, so it unfurls instead of just zooming, while it fades in.
- Close: fades and shrinks to 0.9 toward the arrow.
- Placement: prefers `placement`, flips to the other side when it does not fit, is clamped 12 pt from the screen edges, and the arrow slides along the bubble to stay on the anchor's center.
- Reduced motion: no growth; the bubble fades in and out.
- Haptic: select when a tooltip opens from a long press
- Haptic: none when tapping or hovering
- The bubble mounts only while open, measures its content once and animates on the UI thread.
Accessibility
- The anchor is a button with accessibilityState expanded and a hint; pass accessibilityLabel when it has no text (an icon).
- A popover bubble is modal for screen readers and announces its title when it opens; tooltips are a polite live region.
- Tap outside, Android back or Escape on the web closes a popover; the anchor gets an 8 pt hitSlop so small icons reach 44 pt.
- An accessibilityLabel on an anchor that shows text must start with that text (web browsers check it); leave it out to let the visible text name the anchor.
Notes for AI
- children is the anchor and becomes the button: pass plain content (an icon, a chip, text), never another Button or Pressable.
- Give rich content a fixed width (for example width: 240) so the bubble measures it once.
- Tooltips (variant='tooltip') take a short string; they open on tap, while held (closing on release) and on hover on the web.
- content can be a function receiving close, for a Done button inside the bubble.
- The bubble is placed when it opens; it does not follow an anchor that scrolls while it is open (popovers block scrolling with their backdrop; hover tooltips close on hover out).
Related
Long-press an element and it lifts out of the page above a dimmed backdrop while a menu springs out beside it; keep the finger down, slide onto an item and release to choose. Right-click opens it on the web.
A centered alert that springs in from slightly larger; touch an action and slide across the others with a tick per action, tap outside and it nudges, and async actions keep it open with a spinner until they settle.
A sheet that rests at detents, follows the finger 1:1, settles with velocity and hands drags off to its scroll view.