import { useState } from "react";
import { Text } from "react-native";
import { Button } from "@/component-lib/button";
import {
Menu,
MenuCheckboxItem,
MenuGroup,
MenuItem,
MenuRadioGroup,
MenuRadioItem,
MenuSeparator,
MenuSub,
} from "@/component-lib/menu";
import { useKitTheme } from "@/component-lib/shared/native";
import { Row, Section } from "./layout"; // Section and Row: page layout for the demo
export function MenuDemo() {
const { tokens } = useKitTheme();
const [last, setLast] = useState("—");
const [wrap, setWrap] = useState(true);
const [density, setDensity] = useState("comfortable");
const items = (
<>
<MenuGroup label="Invoice">
<MenuItem onSelect={() => setLast("Edit")} shortcut="⌘E">
Edit
</MenuItem>
<MenuItem onSelect={() => setLast("Duplicate")}>Duplicate</MenuItem>
<MenuSub label="Export as">
<MenuItem onSelect={() => setLast("PDF")}>PDF</MenuItem>
<MenuItem onSelect={() => setLast("CSV")}>CSV</MenuItem>
<MenuSub label="Spreadsheet">
<MenuItem onSelect={() => setLast("XLSX")}>Excel (.xlsx)</MenuItem>
<MenuItem disabled>Google Sheets</MenuItem>
</MenuSub>
</MenuSub>
<MenuItem disabled>Send reminder</MenuItem>
</MenuGroup>
<MenuSeparator />
<MenuCheckboxItem checked={wrap} onCheckedChange={setWrap}>
Wrap long lines
</MenuCheckboxItem>
<MenuRadioGroup label="Density" value={density} onValueChange={setDensity}>
<MenuRadioItem value="compact">Compact</MenuRadioItem>
<MenuRadioItem value="comfortable">Comfortable</MenuRadioItem>
</MenuRadioGroup>
<MenuSeparator />
<MenuItem destructive onSelect={() => setLast("Delete")}>
Delete invoice
</MenuItem>
</>
);
return (
<Section title="Menu · items, groups, submenus">
<Row>
<Menu trigger={<Button variant="outline">Actions (auto)</Button>} label="Invoice actions">
{items}
</Menu>
<Menu trigger={<Button variant="outline">As popover</Button>} presentation="popover">
{items}
</Menu>
</Row>
<Text style={{ color: tokens.muted }}>
Last: {last} · wrap {wrap ? "on" : "off"} · {density}
</Text>
</Section>
);
}Install
npx @grampro/kit@native add MenuUsage
import { Menu, MenuItem } from "@/component-lib/menu";
<Menu trigger={<Button variant="outline">Actions</Button>}>
<MenuItem onSelect={duplicate}>Duplicate</MenuItem>
<MenuItem onSelect={archive}>Archive</MenuItem>
</Menu>Props
MenuProps
| Prop | Type | Description |
|---|---|---|
trigger (required) | ReactElement<TriggerProps> | The element that opens the menu, cloned with a ref (to measure where it is) and an onPress. Any Kit button, or any Pressable, works. |
children (required) | ReactNode | |
open | boolean | Controlled open state. |
defaultOpen | boolean | Open to begin with, when you are not controlling open. |
onOpenChange | (open: boolean, reason?: MenuCloseReason) => void | reason is outside (tap outside or Android back), trigger, select or api, and undefined when opening. |
label | string | Names the menu for screen readers. Defaults to the locale text. |
side | MenuSide | Default bottom. Popover presentation only. |
align | MenuAlign | Default start. Popover presentation only. |
gap | number | Distance from the trigger. Default 4. |
closeOnSelect | boolean | Close the menu when an item is chosen. Default true. |
presentation | "auto" | "sheet" | "popover" | auto (default): an action sheet on phones, a popover on tablets. Or force sheet or popover. |
style | StyleProp<ViewStyle> | The list's style. |
styles | MenuStyles | |
localeText | Partial<MenuLocaleText> |
MenuItemProps
| Prop | Type | Description |
|---|---|---|
onSelect | () => void | Called when the item is chosen. |
closeOnSelect | boolean | Keep the menu open after choosing. Defaults to the Menu's closeOnSelect. |
children (required) | ReactNode | |
icon | ReactNode | Drawn before the label. |
shortcut | ReactNode | A hint such as ⌘K, for hardware keyboards. The menu shows it; binding the key is up to you. |
disabled | boolean | |
destructive | boolean | Styles it as a destructive action. |
style | StyleProp<ViewStyle> |
MenuSubProps
| Prop | Type | Description |
|---|---|---|
label (required) | ReactNode | The label of the item that opens the submenu. |
children (required) | ReactNode | |
icon | ReactNode | Drawn before the submenu's label. |
disabled | boolean | |
style | StyleProp<ViewStyle> |
Native and web
- In a sheet, a submenu replaces the list with a back row.
- Web version: Menu on the web.