import { useState } from "react";
import { Text, View } from "react-native";
import { Button } from "@/component-lib/button";
import { Popover } from "@/component-lib/popover";
import { useKitTheme } from "@/component-lib/shared/native";
import { Row, Section } from "./layout"; // Section and Row: page layout for the demo
export function PopoverDemo() {
const { tokens } = useKitTheme();
const [reason, setReason] = useState("—");
return (
<>
<Section title="Popover · anchored">
<Row>
<Popover
trigger={<Button variant="outline">Help</Button>}
title="What is GST?"
description="Goods and Services Tax, charged on most sales in India."
onOpenChange={(open, why) => setReason(open ? "opened" : (why ?? "?"))}
>
Your invoices show it per line, at the rate set on each product.
</Popover>
<Popover trigger={<Button variant="outline">Filters</Button>} aria-label="Filters" side="bottom" align="end">
{({ close }) => (
<View style={{ gap: 10 }}>
<Text style={{ color: tokens.fg }}>Only unpaid invoices</Text>
<Button size="sm" onPress={close}>
Apply
</Button>
</View>
)}
</Popover>
</Row>
<Text style={{ color: tokens.muted }}>Last close reason: {reason}</Text>
</Section>
<Section title="Popover · as a sheet">
<Popover
presentation="sheet"
trigger={<Button variant="secondary">Share settings</Button>}
title="Share settings"
description="People with the link can view this invoice."
>
The link expires in 7 days. Revoke it any time from Settings.
</Popover>
</Section>
</>
);
}Install
npx @grampro/kit@native add PopoverUsage
import { Popover } from "@/component-lib/popover";
<Popover trigger={<Button variant="outline">Details</Button>} title="GST">
<Text>18% on services.</Text>
</Popover>Props
PopoverProps
| Prop | Type | Description |
|---|---|---|
trigger (required) | ReactElement<TriggerProps> | The element that opens it, cloned with a ref (to measure where it is) and an onPress. Any Kit button, or any Pressable, works. |
children | ReactNode | ((props: PopoverRenderProps) => ReactNode) | |
open | boolean | Controlled open state. |
defaultOpen | boolean | Open to begin with, when you are not controlling open. |
onOpenChange | (open: boolean, reason?: PopoverCloseReason) => void | reason is outside (tap outside or Android back), trigger or api, and undefined when opening. |
title | ReactNode | Heading inside the panel, which also names it. |
description | ReactNode | A line under the title. |
side | PopoverSide | Side of the trigger to open on, before flipping for space. Default bottom. |
align | PopoverAlign | Default start. |
gap | number | Distance from the trigger, in dp. Default 6. |
scrollable | boolean | Cap the panel to the space available and let it scroll. Default false. |
presentation | "auto" | "popover" | "sheet" | popover anchors it to the trigger (default); sheet opens a bottom sheet; auto picks a sheet on phones and a popover on tablets. |
style | StyleProp<ViewStyle> | The panel's style (the web's className on the panel). |
styles | Partial<{ panel: StyleProp<ViewStyle>; header: StyleProp<ViewStyle>; title: StyleProp<T… | |
localeText | Partial<PopoverLocaleText> |
Native and web
- Android back and a tap outside both close with reason
outside. - Web version: Popover on the web.