Implementing Context Menu for iOS App
Context Menu in iOS 13+ is UIMenu + UIContextMenuInteraction. Correctly implemented context menu works identically on long press on Haptic Touch devices, on press with force on 3D Touch devices, and on right click on iPad with trackpad or Magic Mouse.
UIContextMenuInteraction for Arbitrary View
class CardView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
let interaction = UIContextMenuInteraction(delegate: self)
addInteraction(interaction)
}
}
extension CardView: UIContextMenuInteractionDelegate {
func contextMenuInteraction(
_ interaction: UIContextMenuInteraction,
configurationForMenuAtLocation location: CGPoint
) -> UIContextMenuConfiguration? {
UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { [weak self] _ in
guard let self = self else { return nil }
let open = UIAction(title: "Open", image: UIImage(systemName: "arrow.up.right")) { _ in
self.handleOpen()
}
let copy = UIAction(title: "Copy", image: UIImage(systemName: "doc.on.doc")) { _ in
self.handleCopy()
}
let delete = UIAction(
title: "Delete",
image: UIImage(systemName: "trash"),
attributes: .destructive
) { _ in
self.handleDelete()
}
// Grouping via UIMenu
let editMenu = UIMenu(title: "", options: .displayInline, children: [copy])
return UIMenu(title: "", children: [open, editMenu, delete])
}
}
}
options: .displayInline for nested UIMenu removes the subgroup title and visually separates items with a horizontal line — standard pattern for separating destructive actions from safe ones.
SwiftUI .contextMenu
struct ItemView: View {
var item: Item
var body: some View {
ItemCard(item: item)
.contextMenu {
Button {
openItem(item)
} label: {
Label("Open", systemImage: "arrow.up.right")
}
Button(role: .destructive) {
deleteItem(item)
} label: {
Label("Delete", systemImage: "trash")
}
} preview: {
ItemPreviewView(item: item)
.frame(width: 300, height: 200)
}
}
}
preview: in SwiftUI — preview on long press, analog of previewProvider in UIKit. Button(role: .destructive) automatically colors item red.
UITableView and UICollectionView
Specialized delegate methods without needing to add UIContextMenuInteraction manually:
// UITableView
func tableView(_ tableView: UITableView,
contextMenuConfigurationForRowAt indexPath: IndexPath,
point: CGPoint) -> UIContextMenuConfiguration? {
// ...
}
// UICollectionView
func collectionView(_ collectionView: UICollectionView,
contextMenuConfigurationForItemsAt indexPaths: [IndexPath],
point: CGPoint) -> UIContextMenuConfiguration? {
// iOS 16+ supports multiple selection
}
Timeline Benchmarks
Context menu for one View type or cell — a few hours. Full implementation for UITableView/UICollectionView with preview and custom actions — 1 working day.







