suiss/uim · React Native Component

Dropdown Menu

A menu of actions or options that opens from a trigger button.

Dropdown Menu is an open-source mobile component from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Dropdown Menu (open by default) on iOS in light mode

DropdownMenu opens DropdownMenuContent next to a DropdownMenuTrigger when it is pressed. The content renders through a portal (inside a full-window overlay on iOS) as a raised, rounded card positioned below the trigger by default.

Items can be plain actions, checkbox items, radio items in a group, or a submenu. DropdownMenuSubContent expands in place under its trigger, and the caret turns to point down while it is open. For a menu that opens on long press at the touch point, use Context Menu.

Installation

$ pnpm dlx @esuiss/uim@latest add dropdown-menu

The CLI also adds what it builds on: Icon, Text.

Manual

  1. Install the dependencies:
npx expo install cn phosphor-react-native react-native-reanimated react-native-screens react-native-svg react-native-worklets
  1. Add the pieces it builds on: Icon, Text, and the primitives components/primitives/menu.tsx, components/primitives/use-render.tsx.

  2. Copy the source into components/ui/dropdown-menu.tsx:

uniwind/components/ui/dropdown-menu.tsx
import { cn } from "cn"
import { CaretRightIcon, CheckIcon } from "phosphor-react-native"
import * as React from "react"
import { Platform, View } from "react-native"
import { FadeIn, ReduceMotion } from "react-native-reanimated"
import { FullWindowOverlay as RNFullWindowOverlay } from "react-native-screens"
import * as MenuPrimitive from "@/components/primitives/menu"
import { resolveClassName } from "@/components/primitives/use-render"
import { AnimatedView } from "@/components/ui/animated-view"
import { Icon } from "@/components/ui/icon"
import { TextClassContext } from "@/components/ui/text"

const DropdownMenu = MenuPrimitive.Root

const DropdownMenuPortal = MenuPrimitive.Portal
  1. Update the import paths to match your project.

Usage

import { DropdownMenuContent, DropdownMenuSubTrigger, DropdownMenuSubContent, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioItem, DropdownMenuLabel, DropdownMenuSeparator } from "@/components/ui/dropdown-menu"
<View className="items-start">
  <DropdownMenu defaultOpen>
    <OpenButton />
    <DropdownMenuContent className="w-56" align="start">
      <DropdownMenuLabel>My account</DropdownMenuLabel>
      <DropdownMenuGroup>
        <DropdownMenuItem>
          <Icon as={UserIcon} className="size-4" />
          <Text>Profile</Text>
        </DropdownMenuItem>
        <DropdownMenuItem>
          <Icon as={CreditCardIcon} className="size-4" />
          <Text>Billing</Text>
        </DropdownMenuItem>
        <DropdownMenuItem>
          <Icon as={GearIcon} className="size-4" />
          <Text>Settings</Text>
        </DropdownMenuItem>
      </DropdownMenuGroup>
      <DropdownMenuSeparator />
      <DropdownMenuSub>
        <DropdownMenuSubTrigger>
          <View className="flex-row items-center gap-2">
            <Icon as={UserPlusIcon} className="size-4" />
            <Text>Invite users</Text>
          </View>
        </DropdownMenuSubTrigger>
        <DropdownMenuSubContent>
          <DropdownMenuItem>
            <Icon as={EnvelopeIcon} className="size-4" />
            <Text>Email</Text>
          </DropdownMenuItem>
          <DropdownMenuItem>
            <Icon as={ChatCircleIcon} className="size-4" />
            <Text>Message</Text>
          </DropdownMenuItem>
        </DropdownMenuSubContent>
      </DropdownMenuSub>
      <DropdownMenuSeparator />
      <DropdownMenuItem variant="destructive">
        <Icon as={SignOutIcon} className="size-4" />
        <Text>Log out</Text>
      </DropdownMenuItem>
    </DropdownMenuContent>
  </DropdownMenu>
</View>

Use render on DropdownMenuTrigger to render it as a Button. Items close the menu when pressed unless closeOnPress={false}.

Use DropdownMenuCheckboxItem with checked and onCheckedChange, and DropdownMenuRadioItem inside a DropdownMenuRadioGroup with value and onValueChange. Group items with DropdownMenuGroup and DropdownMenuLabel, and divide sections with DropdownMenuSeparator.

Set variant="destructive" on an item that deletes or removes. Use inset on items without an icon to align them with items that have one. Position the content with side, align, sideOffset and alignOffset.

Examples

Default

iOS
Dropdown Menu on iOS in light mode

Checkboxes

Checkbox items that toggle panels on and off.

iOS
Dropdown Menu (checkboxes) on iOS in light mode

Radio group

Radio items that pick one value.

iOS
Dropdown Menu (radio group) on iOS in light mode

Inset

Items aligned with inset.

iOS
Dropdown Menu (inset) on iOS in light mode

API Reference

Floating menu card.

ExtendsReact.ComponentProps<typeof MenuPrimitive.Popup>PositionerProps
PropType
About
Name of the portal host to render into.
Type
string
Default
—

Row that expands the submenu.

ExtendsReact.ComponentProps<typeof MenuPrimitive.SubmenuTrigger>
PropType
Type
React.ReactNode
Default
—
About
Extra classes for the caret icon.
Type
string
Default
—
About
Adds start padding.
Type
boolean
Default
—

Items of the submenu.

ExtendsReact.ComponentProps<typeof MenuPrimitive.Popup>

Action row.

ExtendsReact.ComponentProps<typeof MenuPrimitive.Item>
PropType
About
Adds start padding to align with icon items.
Type
boolean
Default
—
About
default or destructive.
Type
"default""destructive"
Default
"default"

Row with a check mark that toggles.

ExtendsReact.ComponentProps<typeof MenuPrimitive.CheckboxItem>
PropType
Type
React.ReactNode
Default
—
About
Adds start padding.
Type
boolean
Default
—

Row that selects one value in its group.

ExtendsReact.ComponentProps<typeof MenuPrimitive.RadioItem>
PropType
Type
React.ReactNode
Default
—
About
Adds start padding.
Type
boolean
Default
—

Heading for a group.

ExtendsReact.ComponentProps<typeof MenuPrimitive.GroupLabel>
PropType
About
Adds start padding.
Type
boolean
Default
—

Line between sections.

ExtendsReact.ComponentProps<typeof MenuPrimitive.Separator>

Accessibility

  • The trigger has the button role.
  • The popup has the menu role; items use menuitem, checkbox and radio roles, and radio groups use radiogroup.
  • Groups are labelled by their DropdownMenuLabel, and separators have the separator role.

Notes

  • Uses bg-surface-raised, bg-item-pressed, bg-item-selected and bg-danger-surface-pressed tokens; light and dark follow the system appearance.
  • The fade-in respects the system Reduce Motion setting.