Context Menu

A menu component triggered by right-click on web and long press on touch devices

ContextMenu opens an accessible menu from a right click on web or a long press on touch devices.

Right Click or Long Press

Features

  • Full keyboard navigation

  • Items, icons, images, checkboxes, and groups

  • Submenu support

  • Modal and non-modal modes

  • Platform-native menus on mobile

  • Custom alignment, offsets, and positioning

  • Native iOS and Android icons

  • Native previews on iOS

ContextMenu displays a menu triggered by right-click on web or long-press on mobile. It supports submenus, native platform menus with iOS previews, and automatically stacks above other content.

Installation

ContextMenu is already installed in tamagui, or you can install it independently:

yarn add @tamagui/context-menu

For Expo 57 and React Native 0.86, use the Expo UI adapter:

yarn add @expo/ui

Then add the setup import at your app entry point:

import '@tamagui/native/setup-expo-ui-menu'

The Zeego adapter remains available for apps on compatible React Native versions:

yarn add @react-native-menu/menu react-native-ios-context-menu react-native-ios-utilities zeego sf-symbols-typescript
import '@tamagui/native/setup-zeego'

On native, ContextMenu.Trigger coordinates with parent Tamagui pressables automatically. You should not need extra wrapper views or empty onPress handlers just to prevent a parent press: clause from activating.

Expo Router users: This import must run before expo-router/entry. Create an index.js at your project root that imports the setup first, then expo-router, and update your package.json main field to "index.js". See the Expo guide for details.

Anatomy

Import all parts and piece them together.

import { ContextMenu } from 'tamagui' // or '@tamagui/context-menu'
export default () => (
<ContextMenu>
<ContextMenu.Trigger asChild>
<YStack>
<Text>Right Click or longPress</Text>
</YStack>
</ContextMenu.Trigger>
<ContextMenu.Portal zIndex={100}>
<ContextMenu.Content>
<ContextMenu.Item>
<ContextMenu.ItemTitle>About Notes</ContextMenu.ItemTitle>
</ContextMenu.Item>
<ContextMenu.Item>
<ContextMenu.ItemTitle>Settings</ContextMenu.ItemTitle>
</ContextMenu.Item>
{/* when title is nested inside a React element then you need to use `textValue` */}
<ContextMenu.Item textValue="Calendar">
<ContextMenu.ItemTitle>
<Text>Calendar</Text>
</ContextMenu.ItemTitle>
<ContextMenu.ItemIcon>
<Calendar color="gray" size="1" />
</ContextMenu.ItemIcon>
</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Sub>
<ContextMenu.SubTrigger>
<ContextMenu.ItemTitle>Actions</ContextMenu.ItemTitle>
</ContextMenu.SubTrigger>
<ContextMenu.Portal zIndex={200}>
<ContextMenu.SubContent>
<ContextMenu.Label fontSize={'1'}>Note settings</ContextMenu.Label>
<ContextMenu.Item onSelect={onSelect} key="create-note">
<ContextMenu.ItemTitle>Create note</ContextMenu.ItemTitle>
</ContextMenu.Item>
<ContextMenu.Item onSelect={onSelect} key="delete-all">
<ContextMenu.ItemTitle>Delete all notes</ContextMenu.ItemTitle>
</ContextMenu.Item>
<ContextMenu.Item onSelect={onSelect} key="sync-all">
<ContextMenu.ItemTitle>Sync notes</ContextMenu.ItemTitle>
</ContextMenu.Item>
</ContextMenu.SubContent>
</ContextMenu.Portal>
</ContextMenu.Sub>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu>
)

API reference

ContextMenu

Contains every component for the ContextMenu.

Props

  • children (required)

    React.ReactNode

    Menu parts: Trigger, Portal, Content, Items, etc.

  • placement

    Placement

    Where the menu appears relative to the trigger. Options: 'top' | 'right' | 'bottom' | 'left' with optional '-start' | '-end' alignment.

  • open

    boolean

    Controlled open state for the menu.

  • defaultOpen

    boolean

    Initial open state when uncontrolled.

  • onOpenChange

    (open: boolean, event?: { preventDefault: () => void }) => void

    Called when the menu opens or closes. Call event.preventDefault() to cancel and allow the native context menu to show instead.

  • onOpenWillChange

    (open: boolean) => void

    Called before the open/close animation begins.

  • modal

    boolean

    Default: 

    true

    When true, traps focus inside the menu and blocks outside scroll/interactions.

  • stayInFrame

    ShiftProps | boolean

    Default: 

    { padding: 10 }

    Shifts the menu horizontally to stay within viewport bounds. Pass an object to customize shift behavior (mainAxis, crossAxis, padding).

  • allowFlip

    FlipProps | boolean

    Default: 

    { padding: 10 }

    Flips the menu to the opposite side if there is insufficient space.

  • offset

    OffsetOptions

    Default: 

    10

    Distance between the menu and its trigger.

  • resize

    boolean

    Default: 

    true

    Constrains the menu to fit within available viewport space.

  • unstyled

    boolean

    Removes all default Tamagui styles.

  • Allowing native context menu

    You can call event.preventDefault() in onOpenChange to prevent the Tamagui menu from opening and allow the native browser context menu to appear instead:

    <ContextMenu onOpenChange={(open, event) => { if (someCondition) { // prevent Tamagui menu, let native context menu show event?.preventDefault() } }} >
    {/* ... */}
    </ContextMenu>

    ContextMenu.Portal

    This is necessary for the ContextMenu.

    Props

  • zIndex

    number

    Stacking order of the portal layer.

  • children (required)

    React.ReactNode

    Content to render inside the portal.

  • forceMount

    true

    Forces the portal to stay mounted, useful for controlling animations.

  • ContextMenu.Trigger

    The ContextMenu will only be triggered when the user right-clicks or long-presses within the Trigger area.

    Props

  • action

    press|longPress

    Default: 

    longPress

    Works with the native prop and accepts 'press' or 'longPress'. The default is 'longPress' for ContextMenu.

  • ContextMenu.Content

    Contains the content of the ContextMenu.

    Props

  • children (required)

    React.ReactNode

    Menu items, groups, labels, separators, and submenus.

  • loop

    boolean

    Default: 

    false

    Whether keyboard navigation wraps from last to first item.

  • forceMount

    true

    Forces the content to stay mounted, useful for controlling animations.

  • onCloseAutoFocus

    (event: Event) => void

    Called when focus returns to the trigger after closing.

  • onEscapeKeyDown

    (event: KeyboardEvent) => void

    Called when the escape key is pressed. Can be prevented.

  • onPointerDownOutside

    (event: PointerEvent) => void

    Called when a pointer event occurs outside the content.

  • onInteractOutside

    (event: Event) => void

    Called when any interaction occurs outside the content.

  • ContextMenu.Item

    A selectable menu item that triggers an action when selected.

    Props

  • key (required)

    string

    Unique identifier for the item.

  • disabled

    boolean

    Default: 

    false

    Prevents interaction and dims the item.

  • destructive

    boolean

    Renders the item in red on iOS to indicate a dangerous action (e.g. delete). No effect on web.

  • hidden

    boolean

    Hides the item from the menu.

  • onSelect

    (event?: Event) => void

    Called when the item is selected via click or keyboard.

  • onFocus

    () => void

    Called when the item receives focus.

  • onBlur

    () => void

    Called when the item loses focus.

  • textValue

    string

    Text used for typeahead and native menus. Required when ItemTitle contains a React node instead of a string.

  • ContextMenu.ItemTitle

    Renders the title of the menu item.

    Props

  • children (required)

    string | React.ReactNode

    The title text or element to display.

  • You can directly pass a text node to the ItemTitle. However, if you use a nested React node like <Text>, you need to pass textValue to the <Item> so that it works with native menus.

    ContextMenu.ItemIcon

    A component to render an icon. For non-native menus, you can pass an icon component. For native menus, you can pass platform-specific icons to the android/ios props.

    On iOS, it renders the native SF Symbols icons.

    Props

  • children

    React.ReactNode

    Fallback icon for web when native icons are not available.

  • ios

    object

    SF Symbol configuration: name, weight, scale, hierarchicalColor, paletteColors.

  • android

    object

    Android resource drawable name.

  • <ContextMenu.ItemIcon ios={{ name: '0.circle.fill', // required pointSize: 5, weight: 'semibold', scale: 'medium', // can also be a color string. Requires iOS 15+ hierarchicalColor: { dark: 'blue', light: 'green', }, // alternative to hierarchical color. Requires iOS 15+ paletteColors: [ { dark: 'blue', light: 'green', }, ], }} >
    <CircleIcon />
    </ContextMenu.ItemIcon>

    ContextMenu.ItemImage

    A component to render an item image. For native menus, it only works on iOS. It takes the same properties as @tamagui/image.

    ContextMenu.ItemSubtitle

    A component to render a subtitle for the menu item. For native menus, it only works on iOS.

    Props

  • children (required)

    string

    The subtitle text to display below the title.

  • ContextMenu.Group

    A component that groups multiple menu items together.

    Props

  • children (required)

    React.ReactNode

    Menu items to group together.

  • ContextMenu.CheckboxItem

    A menu item with a checkbox that can be toggled on/off.

    Props

  • key (required)

    string

    Unique identifier for the checkbox item.

  • disabled

    boolean

    Default: 

    false

    Prevents interaction and dims the item.

  • destructive

    boolean

    Renders the item in red on iOS to indicate a dangerous action. No effect on web.

  • hidden

    boolean

    Hides the item from the menu.

  • onFocus

    () => void

    Called when the item receives focus.

  • onBlur

    () => void

    Called when the item loses focus.

  • textValue

    string

    Text for native menus. Required when ItemTitle contains a React node.

  • value

    'on' | 'off' | 'mixed'

    Controlled checked state for native menus.

  • onValueChange

    (state, prevState) => void

    Called when checked state changes on native menus.

  • checked

    boolean

    Controlled checked state for web menus.

  • onCheckedChange

    (checked: boolean) => void

    Called when checked state changes on web.

  • ContextMenu.ItemIndicator

    Use inside CheckboxItem or RadioItem to indicate when an item is checked. This allows you to conditionally render a checkmark.

    <ContextMenu.ItemIndicator>
    <CheckmarkIcon /> {/* This does not work with the native prop. */}
    </ContextMenu.ItemIndicator>

    Props

  • children

    React.ReactNode

    Custom checkmark icon. Only works on web.

  • forceMount

    true

    Forces the indicator to stay mounted for animation control.

  • ContextMenu.Label

    Renders a non-focusable label for a group of items. On native menus, only one label is supported per menu and submenu.

    Props

  • children (required)

    string

    The label text.

  • textValue

    string

    Text for native menus when children is a React node.

  • ContextMenu.Arrow

    Renders an arrow pointing to the trigger.

    Props

  • size

    number | SizeToken

    Width and height of the arrow.

  • unstyled

    boolean

    Removes default arrow styles.

  • ContextMenu.Separator

    Renders a visual divider between menu items. Web only.

    ContextMenu.Sub

    A container for nested sub-menu components.

    Props

  • children (required)

    React.ReactNode

    SubTrigger, Portal, and SubContent components.

  • open

    boolean

    Controlled open state for the sub-menu.

  • onOpenChange

    (open: boolean) => void

    Called when the sub-menu opens or closes.

  • ContextMenu.SubContent

    Renders the content of a sub-menu. Same props as Content.

    ContextMenu.SubTrigger

    A menu item that opens a sub-menu on hover/focus. Accepts the same props as Item.

    ContextMenu.Preview

    When the ContextMenu is visible, this renders a custom preview component. Only works with native iOS menus.

    Should be rendered as a child of ContextMenu.Content.

    Props

  • children (required)

    React.ReactNode | (() => React.ReactNode)

    The preview content to render. Can be a function for lazy rendering.

  • size

    { width?: number, height?: number }

    Dimensions of the preview.

  • onPress

    () => void

    Called when the preview is pressed.

  • backgroundColor

    string | { dark: string, light: string }

    Background color of the preview.

  • borderRadius

    number

    Border radius of the preview.

  • preferredCommitStyle

    'pop' | 'dismiss'

    Default: 

    'dismiss'

    Exit transition when preview is tapped. Use 'pop' when navigating to another screen.

  • <ContextMenu.Preview // optional props: preferredCommitStyle="pop" // or "dismiss" backgroundColor={{ // or a color string directly dark: 'black', light: 'white', }} >
    {() => <Preview />}
    </ContextMenu.Preview>