This documentation is available as Markdown for AI agents and LLMs. See the full Markdown index or append .md to any documentation URL.
This is documentation for the next SDK version. For up-to-date documentation, see the
latest version (SDK 57).
ContextMenu A SwiftUI ContextMenu component for displaying context menus.
Expo UI ContextMenu matches the official SwiftUI contextMenu API and displays a menu when long-pressed. For single-tap menu interactions, use Menu instead.
Installation
- npx expo install @expo/ui
- yarn expo install @expo/ui
- pnpm expo install @expo/ui
- bun expo install @expo/ui
If you are installing this in an existing React Native app , make sure to install expo in your project.
Usage
BasicContextMenuExample.tsx import { Host , ContextMenu , Button , Text } from '@expo/ui/swift-ui' ;
export default function BasicContextMenuExample ( ) {
return (
< Host style = { { flex: 1 } } >
< ContextMenu >
< ContextMenu.Items >
< Button
label = " Edit"
onPress = { ( ) => console . log ( 'Edit' ) }
/>
< Button
label = " Delete"
role = " destructive"
onPress = { ( ) => console . log ( 'Delete' ) }
/>
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Text > Long press me </ Text >
</ ContextMenu.Trigger >
</ ContextMenu >
</ Host >
) ;
}
ContextMenuWithImagesExample.tsx import { Host , ContextMenu , Button , Text } from '@expo/ui/swift-ui' ;
export default function ContextMenuWithImagesExample ( ) {
return (
< Host style = { { flex: 1 } } >
< ContextMenu >
< ContextMenu.Items >
< Button
label = " Share"
systemImage = " square.and.arrow.up"
onPress = { ( ) => console . log ( 'Share' ) }
/>
< Button
label = " Favorite"
systemImage = " heart"
onPress = { ( ) => console . log ( 'Favorite' ) }
/>
< Button
label = " Delete"
systemImage = " trash"
role = " destructive"
onPress = { ( ) => console . log ( 'Delete' ) }
/>
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Text > Long press me </ Text >
</ ContextMenu.Trigger >
</ ContextMenu >
</ Host >
) ;
}
Use ContextMenu.Preview to show a custom preview above the menu when opened.
ContextMenuWithPreviewExample.tsx import { View , Text as RNText } from 'react-native' ;
import {
Host ,
ContextMenu ,
Button ,
RNHostView ,
Text ,
} from '@expo/ui/swift-ui' ;
export default function ContextMenuWithPreviewExample ( ) {
return (
< Host style = { { flex: 1 } } >
< ContextMenu >
< ContextMenu.Items >
< Button
label = " Edit"
onPress = { ( ) => console . log ( 'Edit' ) }
/>
< Button
label = " Delete"
role = " destructive"
onPress = { ( ) => console . log ( 'Delete' ) }
/>
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Text > Long press me </ Text >
</ ContextMenu.Trigger >
< ContextMenu.Preview >
< RNHostView matchContents >
< View
style = { {
width: 200 ,
height: 100 ,
backgroundColor: '#f0f0f0' ,
padding: 16 ,
} } >
< RNText > Preview content </ RNText >
</ View >
</ RNHostView >
</ ContextMenu.Preview >
</ ContextMenu >
</ Host >
) ;
}
ContextMenuWithPickerExample.tsx import { useState } from 'react' ;
import {
Host ,
ContextMenu ,
Button ,
Text ,
Picker ,
} from '@expo/ui/swift-ui' ;
import { pickerStyle, tag } from '@expo/ui/swift-ui/modifiers' ;
export default function ContextMenuWithPickerExample ( ) {
const [ selectedIndex, setSelectedIndex] = useState <
number | undefined
> ( 0 ) ;
return (
< Host style = { { flex: 1 } } >
< ContextMenu >
< ContextMenu.Items >
< Button
label = " Action"
onPress = { ( ) => console . log ( 'Action' ) }
/>
< Picker
label = " Size"
modifiers = { [ pickerStyle ( 'menu' ) ] }
selection = { selectedIndex}
onSelectionChange = { setSelectedIndex} >
{ [ 'Small' , 'Medium' , 'Large' ] . map ( ( option, index) => (
< Text key = { index} modifiers = { [ tag ( index) ] } >
{ option}
</ Text >
) ) }
</ Picker >
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Text > Long press me </ Text >
</ ContextMenu.Trigger >
</ ContextMenu >
</ Host >
) ;
}
Use Section and Divider components to organize menu items.
ContextMenuWithSectionsExample.tsx import {
Host ,
ContextMenu ,
Button ,
Text ,
Section ,
Divider ,
} from '@expo/ui/swift-ui' ;
export default function ContextMenuWithSectionsExample ( ) {
return (
< Host style = { { flex: 1 } } >
< ContextMenu >
< ContextMenu.Items >
< Section title = " Actions" >
< Button
label = " Edit"
onPress = { ( ) => console . log ( 'Edit' ) }
/>
< Button
label = " Duplicate"
onPress = { ( ) => console . log ( 'Duplicate' ) }
/>
</ Section >
< Divider />
< Button
label = " Delete"
role = " destructive"
onPress = { ( ) => console . log ( 'Delete' ) }
/>
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Text > Long press me </ Text >
</ ContextMenu.Trigger >
</ ContextMenu >
</ Host >
) ;
}
Disabled items
Use the disabled(true) modifier on a menu Button to render it greyed-out and non-interactive.
DisabledContextMenuItemExample.tsx import { Host , ContextMenu , Button , Text } from '@expo/ui/swift-ui' ;
import { disabled } from '@expo/ui/swift-ui/modifiers' ;
export default function DisabledContextMenuItemExample ( ) {
return (
< Host style = { { flex: 1 } } >
< ContextMenu >
< ContextMenu.Items >
< Button
label = " Edit"
onPress = { ( ) => console . log ( 'Edit' ) }
/>
< Button
label = " Locked"
systemImage = " lock"
modifiers = { [ disabled ( true ) ] }
onPress = { ( ) => console . log ( 'This never fires' ) }
/>
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Text > Long press me </ Text >
</ ContextMenu.Trigger >
</ ContextMenu >
</ Host >
) ;
}
Selectable items (checkmarks)
A SwiftUI Toggle inside ContextMenu.Items automatically renders as a row with a leading SF Symbol and a trailing checkmark when isOn is true.
CheckmarkContextMenuItemExample.tsx import { Host , ContextMenu , Toggle , Text } from '@expo/ui/swift-ui' ;
import { useState } from 'react' ;
export default function CheckmarkContextMenuItemExample ( ) {
const [ pinned, setPinned] = useState ( false ) ;
return (
< Host style = { { flex: 1 } } >
< ContextMenu >
< ContextMenu.Items >
< Toggle
isOn = { pinned}
label = " Pin"
systemImage = " pin"
onIsOnChange = { setPinned}
/>
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Text > Long press me </ Text >
</ ContextMenu.Trigger >
</ ContextMenu >
</ Host >
) ;
}
Use nested ContextMenu components to create submenus.
NestedContextMenuExample.tsx import { Host , ContextMenu , Button , Text } from '@expo/ui/swift-ui' ;
export default function NestedContextMenuExample ( ) {
return (
< Host style = { { flex: 1 } } >
< ContextMenu >
< ContextMenu.Items >
< Button
label = " Action"
onPress = { ( ) => console . log ( 'Action' ) }
/>
< ContextMenu >
< ContextMenu.Items >
< Button
label = " Sub Action 1"
onPress = { ( ) => console . log ( 'Sub 1' ) }
/>
< Button
label = " Sub Action 2"
onPress = { ( ) => console . log ( 'Sub 2' ) }
/>
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Button label = " More Options" />
</ ContextMenu.Trigger >
</ ContextMenu >
</ ContextMenu.Items >
< ContextMenu.Trigger >
< Text > Long press me </ Text >
</ ContextMenu.Trigger >
</ ContextMenu >
</ Host >
) ;
}
API
import { ContextMenu } from '@expo/ui/swift-ui' ;
No API data file found, sorry!