Context Menu

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

Right Click or Long Press

Features

  • Full keyboard navigation.

  • Supports items, icons, images, checkboxes, groups, and more.

  • Supports submenus.

  • Supports modal and non-modal modes.

  • Supports native menus on native platforms.

  • Customizable alignment, offsets, and positioning.

  • Support for native iOS and Android icons.

  • Supports 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

If you want to use native menus, add these dependencies:

yarn add @react-native-menu/menu
yarn add react-native-ios-context-menu
yarn add react-native-ios-utilities
yarn add zeego
yarn add sf-symbols-typescript

Then add the setup import at your app entry point:

import '@tamagui/native/setup-zeego'

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 upgrade 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

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

  • offset

    OffsetOptions

    Distance between the menu and its trigger.

  • 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, excluding side and align.

    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>