A seamless drop-in replacement for UIMenu & UIAction, featuring nested menu support, dark mode compatibility, and Liquid Glass effects.
The inspiration behind this project stems from Apple's lack of a unified interface across iOS and Mac Catalyst apps, as well as the absence of a built-in menu presentation method. To address these gaps—and to enable greater customization—we developed ChidoriMenu.
This project draws heavily on code from ChidoriMenu, and as such, we adhere to the same license.
- Added support for UIMenu & UIAction
- Added drop-in replacement for
_presentMenuAtLocation:
(not recommended for general use) - Added support for nested menus in child elements
- Added support for the
.displayInline
menu option - Added compatibility with dark mode
- Fixed scrolling issues during selection
- Fixed multiple actions triggering simultaneously
- Added support for UIDeferredMenuElement with backward compatibility
- NEW in 4.0.0: Liquid Glass blur effects for modern UI aesthetics
- NEW in 4.0.0: Improved disabled state handling with consistent alpha management
- NEW in 4.0.0: Refactored menu sizing logic for better layout reliability
- iOS 13.0 or later
- macCatalyst 13.0 or later
Getting started is straightforward. While the interface differs slightly from Apple's menu implementation, the core principles remain the same. Mac Catalyst is fully supported, though it does not bridge to AppKit menus—it functions identically to iOS.
UIButton.presentMenu()
UIView.present(menu: menu)
For detailed examples, check out the example project included in the repository.
Enable modern blur effects for a premium UI experience:
ChidoriMenuConfiguration.prefersLiquidGlass = true
Improved consistency in disabled menu item appearance with unified alpha management across all UI elements.
More reliable layout calculations with proper height clamping and width caching for optimal menu presentation.
ChidoriMenu provides comprehensive support for UIMenuElement attributes with proper visual feedback and behavior:
- Prevents selection and execution of menu items
- Applies consistent dimmed appearance with alpha reduction
- Works for both actions and submenus
UIAction(title: "Disabled Action", attributes: .disabled) { _ in
// This action won't execute
}
- Displays actions in red text color for destructive operations
- Can be combined with disabled state for destructive-but-unavailable actions
UIAction(title: "Delete", attributes: .destructive) { _ in
// Destructive action
}
- Action executes without dismissing the menu
- Perfect for toggle switches, counters, and status updates
- Menu automatically refreshes to show updated state
if #available(iOS 16.0, *) {
UIAction(title: "Toggle", attributes: [.keepsMenuPresented]) { action in
action.state = action.state == .on ? .off : .on
}
}
Attributes can be combined for complex scenarios:
// Disabled destructive action
UIAction(title: "Delete", attributes: [.disabled, .destructive]) { _ in }
// Keeps menu presented with state changes
UIAction(title: "Counter", attributes: [.keepsMenuPresented]) { action in
let count = Int(action.subtitle ?? "0") ?? 0
action.subtitle = "\(count + 1)"
}
ChidoriMenu provides full backward compatibility for UIDeferredMenuElement
, including support for future iOS versions. Starting from iOS 26, Apple removed the elementProvider
property from UIDeferredMenuElement
. ChidoriMenu automatically detects this change and dynamically adds the missing functionality through runtime hooking, ensuring your existing code continues to work seamlessly across all iOS versions.
This implementation:
- Hooks the
elementWithProvider:
andelementWithUncachedProvider:
factory methods - Dynamically adds the
elementProvider
property when missing - Maintains proper block lifecycle management
- Works transparently with existing Swift code
ChidoriMenu is available under the MIT license. See the LICENSE file for more info.
2025.9.29 - Version 4.0.0 - Made with ❤️ by Lakr233