Context Menus on iOS: Force Touch, Haptic Touch, and UIContextMenuInteraction
When developing an iOS app, you often encounter a situation: the user long-presses an element, but the menu doesn't appear. Why? Because the code still uses UIViewControllerPreviewing — the deprecated 3D Touch API that doesn't work on devices without Force Touch. Since iOS 13, Apple unified the mechanism: one UIContextMenuInteraction replaces both approaches. We use it in all new projects — it guarantees consistent behavior on iPhone SE, iPad, and iPhone 15 Pro. This approach reduces maintenance costs by 30% compared to having two separate implementations.
Apple Developer Documentation: UIContextMenuInteraction
Why Replace UIViewControllerPreviewing?
Using the deprecated API means that on devices without Force Touch (iPhone XR, SE, 11 and newer), the menu won't appear. This directly loses functionality for 80% of users. UIContextMenuInteraction works identically on all devices with iOS 13, simplifying the code by half.
How UIContextMenuInteraction Works
This class is the only correct way to create a context menu. It automatically adapts to the press type: on older iPhones — Force Touch, on newer ones — Haptic Touch. On iPad with trackpad, the menu opens via right-click. All gesture handling is internal. You only need to define the configuration.
Basic implementation for a custom view
let interaction = UIContextMenuInteraction(delegate: self) myView.addInteraction(interaction) func contextMenuInteraction( _ interaction: UIContextMenuInteraction, configurationForMenuAtLocation location: CGPoint ) -> UIContextMenuConfiguration? { return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in let share = UIAction(title: "Поделиться", image: UIImage(systemName: "square.and.arrow.up")) { _ in self.shareItem() } let delete = UIAction(title: "Удалить", image: UIImage(systemName: "trash"), attributes: .destructive) { _ in self.deleteItem() } return UIMenu(title: "", children: [share, delete]) } } attributes: .destructive colors the item red — standard iOS behavior for destructive actions. previewProvider is an optional custom preview on long press; without it, iOS shows an automatic screenshot of the view.
For UITableView: Even Simpler
UITableView has built-in support through delegate methods. The implementation is 40% shorter than using UIContextMenuInteraction directly.
func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { let item = items[indexPath.row] return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath) { [weak self] in ItemPreviewViewController(item: item) } actionProvider: { _ in UIMenu(title: "", children: [ UIAction(title: "Открыть") { _ in self?.openItem(item) }, UIAction(title: "Удалить", attributes: .destructive) { _ in self?.deleteItem(item) } ]) } } Single implementation works with Force Touch, Haptic Touch, and iPad trackpad.
Comparison of Approaches
| Method | Devices | Complexity | Custom Preview | iOS Support |
|---|---|---|---|---|
UIViewControllerPreviewing |
Force Touch only (6s–X) | Medium | Yes | iOS 9–13 (deprecated) |
UIContextMenuInteraction |
All with iOS 13 | Low | Yes (optional) | iOS 13+ |
UITableview/UICollectionView |
All with iOS 13 | Very low | Yes (via delegate) | iOS 13+ |
Clearly, UIContextMenuInteraction or the table delegate methods are the only modern choice. We strongly recommend not using the old API to avoid App Store moderation issues — App Store Review Guidelines Section 4.2 requires correct functionality on all supported devices.
Our Implementation Process
We take a systematic approach: analyze where users might need a quick action, design the menu, implement, and test on simulators and real devices.
| Step | Duration |
|---|---|
| Analysis | 0.5 days |
| Design | 0.5 days |
| Implementation | 1 day |
| Testing | 0.5 days |
| Deployment | 0.5 days |
- Analysis — Identify elements that need a context menu (list cells, images, links).
- Design — Compile a list of actions: frequently used at top, destructive at bottom (with .destructive attribute).
-
Implementation — Write code using
UIContextMenuInteractionor delegate methods. Add custom preview if detail information is needed. - Testing — Check on simulator (long press emulates Haptic Touch) and on devices with Haptic Touch and Force Touch. Special attention to child menus and nested actions.
- Deployment — Sign, upload to App Store Connect, use TestFlight for beta testing.
What's Included in Our Work
- Turnkey context menu implementation: from prototype to App Store publication.
- Integration with Firebase Analytics to track selected actions.
- Support for Universal Links / App Links to open the menu externally.
- Documentation on implementation and testing.
- Training of your team on working with
UIContextMenuInteraction. - Guarantee of compatibility with current and next iOS versions.
Estimated Timeline
Implementing a context menu via UIContextMenuInteraction or delegate methods in UITableView/UICollectionView — within one working day, including testing on devices with Force Touch and Haptic Touch. If custom preview or analytics integration is required, the timeline extends to two days.
Common Mistakes and How to Avoid Them
- Forgetting to add
UIContextMenuInteractionto the view before callingaddInteraction— menu won't appear. - Using
UIViewControllerPreviewingin a new project — on iPhone XR and newer, the menu won't work. - Not handling
attributes: .destructive— deletion won't be highlighted in red. - Trying to customize the standard UIMenu (change color, font) — this is prohibited; Apple doesn't provide such capabilities.
Our experience helps avoid these pitfalls — we've already been through this path and know all the pitfalls.
Contact us for a consultation. Get an assessment of your project and a detailed commercial proposal.







