Adding Menus Using Material Design in React Native
Adding Menus Using Material Design
~9 Min. Lesezeit Zuletzt aktualisiert am August 8, 2026
A dropdown/context menu ("3-dot menu") is everywhere in Material Design – React Native has no built-in component for it, but the pattern can be built yourself with Modal and absolute positioning.
1. Description
The trick: the menu's option list is rendered inside a transparent, full-screen Modal that overlays the rest of the content. Tapping OUTSIDE the menu (on the transparent background) closes it – the usual behavior for context menus.
2. Short example
<Modal transparent visible={open} onRequestClose={() => setOpen(false)}>
<Pressable style={{ flex: 1 }} onPress={() => setOpen(false)}>
<View style={styles.menu}>{/* menu items */}</View>
</Pressable>
</Modal>3. Complete project: a card action menu
npx create-expo-app material-menu-demo
cd material-menu-demoimport { useState } from 'react';
import { View, Text, TouchableOpacity, Modal, Pressable, StyleSheet } from 'react-native';
function ActionMenu({ options }) {
const [open, setOpen] = useState(false);
function selectOption(option) {
setOpen(false);
option.onPress();
}
return (
<>
<TouchableOpacity onPress={() => setOpen(true)} style={styles.trigger}>
<Text style={styles.dots}>⋮</Text>
</TouchableOpacity>
<Modal transparent visible={open} animationType="fade" onRequestClose={() => setOpen(false)}>
<Pressable style={styles.backdrop} onPress={() => setOpen(false)}>
<View style={styles.menu}>
{options.map((option) => (
<TouchableOpacity
key={option.label}
style={styles.menuItem}
onPress={() => selectOption(option)}
>
<Text style={[styles.menuText, option.danger && styles.dangerText]}>
{option.label}
</Text>
</TouchableOpacity>
))}
</View>
</Pressable>
</Modal>
</>
);
}
const styles = StyleSheet.create({
trigger: { padding: 8 },
dots: { fontSize: 20 },
backdrop: { flex: 1, backgroundColor: 'rgba(0,0,0,0.2)', alignItems: 'flex-end', paddingTop: 100, paddingRight: 16 },
menu: { backgroundColor: 'white', borderRadius: 8, elevation: 4, shadowColor: '#000', shadowOpacity: 0.2, shadowRadius: 6, minWidth: 160, paddingVertical: 4 },
menuItem: { paddingVertical: 12, paddingHorizontal: 16 },
menuText: { fontSize: 15 },
dangerText: { color: '#dc2626' },
});
export default ActionMenu;import { View, Text, Alert, StyleSheet } from 'react-native';
import ActionMenu from './components/ActionMenu';
export default function App() {
const options = [
{ label: 'Edit', onPress: () => Alert.alert('Edit selected') },
{ label: 'Share', onPress: () => Alert.alert('Share selected') },
{ label: 'Delete', onPress: () => Alert.alert('Delete selected'), danger: true },
];
return (
<View style={styles.header}>
<Text style={styles.title}>My Notes</Text>
<ActionMenu options={options} />
</View>
);
}
const styles = StyleSheet.create({
header: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingTop: 60, paddingHorizontal: 16 },
title: { fontSize: 20, fontWeight: 'bold' },
});4. Explanation
transparentonModalkeeps the screen behind it VISIBLE (darkened instead of fully hidden), rather than replacing it with a dedicated full-screen screen.- The outer
Pressablecovers the ENTIRE screen – tapping ANYWHERE outside the actual menu closes it, standard behavior for context menus/dropdowns. onRequestCloseis MANDATORY on Android – it intercepts the back button/back gesture and closes the menu, instead of the app ignoring the modal.- The
optionsprop is an array of objects withlabel/onPress/an optionaldangerflag – the component itself knows nothing about the concrete actions, which makes it reusable for ANY menu (not just notes).