YNDropDownMenu: a Swift 6 dropdown that shows whatever view you hand it
✨ Awesome Dropdown menu for iOS with Swift 5.0
At a glance
- What is it?
- YNDropDownMenu is an iOS dropdown control written in Swift 6, initialised with a frame, an array of views and an array of titles, and it exposes a surprising amount of per-item state, including three visual states and a deprecated API kept alive for source compatibility. It is UIKit only, and the jump from 3.1.0 in 2019 to 4.0.0 in 2026 is the Swift 6 modernisation.
- Who is it for?
- Adopt YNDropDownMenu if you are building a UIKit iOS application and want a dropdown whose content is a view you control rather than a table view the control owns, and you are on iOS 13 or later with a Swift 6 toolchain. Do not adopt it for a SwiftUI project, since there is no SwiftUI interface described, and do not adopt it if you need an actively maintained component, because the version history jumps from 3.1.0 in 2019 to 4.0.0 in 2026.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 40 days ago.
- What is it written in?
- Mainly Swift, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The content is your view, not the control's table
YNDropDownMenu is a dropdown menu for iOS, and the design decision is stated in the introduction: it displays a view of related items when the user taps the menu, and you can customise the dropdown view however you like, for example a UITableView or a UICollectionView.
The initialiser takes a frame, an array of views and an array of titles:
let dropDownMenu = YNDropDownMenu(
frame: CGRect(x: 0, y: 64, width: view.bounds.width, height: 38),
dropDownViews: dropDownViews,
dropDownViewTitles: ["Apple", "Banana", "Kiwi", "Pear"]
)
view.addSubview(dropDownMenu)That is the whole integration. There is no data source, no delegate and no row model, because the control does not own the content. A title bar of your own views, each hidden until its item is selected.
The consequence is that the control is small and that the application code is larger than it would be with a table-backed menu. For a menu with six fixed options, a table view inside the dropdown is a few lines; with this control it is a view you lay out and keep in sync with the titles array.
The frame in the example is also worth noting, because the control is laid out by frame rather than by Auto Layout in the documented usage. The widths of the titles and the items are matched by the control, and the height of 38 in the example is the height of the bar itself, not of the dropdown.
Two package managers, and a floor at iOS 13
The library ships through both Swift Package Manager and CocoaPods, and the README documents each.
For Swift Package Manager, in Xcode you choose File and then Add Package Dependencies and enter the repository URL, or you add the dependency to `Package.swift` yourself:
dependencies: [
.package(url: "https://github.com/younatics/YNDropDownMenu.git", from: "4.0.0")
]For CocoaPods, it is a line in the Podfile:
pod 'YNDropDownMenu', '~> 4.0.0'The requirements are stated in one line: the library is written in Swift 6.0 and requires iOS 13.0 or later, the package manifest uses Swift tools 6.0, and the CocoaPods deployment target is iOS 13.0. The podspec in the repository is the place to check the second figure, since the two are maintained separately.
The version story is the more interesting part. The release list shows 4.0.0 from 2026-07-07, described as the Swift 6 modernisation, then 3.1.0 from 2019-03-31 with Swift 5 support, and 3.0.4 from 2019-02-08. So the project was stable on Swift 5 for a long time and then took a seven year gap to modernise.
That gap is visible in the API. The README has a section titled Deprecated, which says the following APIs remain available for source compatibility and that their replacements should be used in new code. The list includes `alwaysSelectedAt(index:)` in favour of `alwaysSelected(at:)`, `disabledMenuAt(index:)` and `enabledMenuAt(index:)` in favour of `disabledMenu(at:)` and `enabledMenu(at:)`, `showAndHideMenuAt(index:)` in favour of `showAndHideMenu(at:)`, and `changeMenuTitleAt(index:title:)` in favour of `changeMenu(title:at:)` inside a `YNDropDownView` subclass.
The old names are there so that an existing app keeps compiling. New code should use the replacements, because the old ones are on their way out.
Subclassing YNDropDownView to react to open and close
The control is a view, but the per-item behaviour lives in a separate class you can subclass, `YNDropDownView`, which is the view that appears when an item is selected.
class DropDownView: YNDropDownView {
// Override methods called when the menu opens and closes.
override func dropDownViewOpened() {
print("dropDownViewOpened")
}
override func dropDownViewClosed() {
print("dropDownViewClosed")
}
func updateMenu() {
// Hide Menu
hideMenu()
// Change Menu Title At Index
changeMenu(title: "Changed", at: 1)
changeMenu(title: "Changed", status: .selected, at: 1)
// Change View At Index
changeView(view: UIView(), at: 3)
// Always Selected Menu
alwaysSelected(at: 0)
normalSelected(at: 0)
}
}The two overridden methods are the hooks for the open and close of the dropdown, and the example prints from them. The `updateMenu` method shows the rest of the API in one place: hiding the menu, changing a title at an index, changing the title with a status, replacing the view at an index, and moving an item between the always-selected and normally-selected states.
That last pair is the most interesting, because the menu has a notion of a permanently selected item, which is how a control like this usually shows the current choice in the bar while still allowing the user to open the list. `alwaysSelected(at:)` marks an item, `normalSelected(at:)` releases it, and the two are not simply inverses of each other in the visual result.
Because these are methods on the view rather than on the menu, you need a reference to the item's view in order to change it, which is why the dropdown views are held in an array that the application keeps.
Three visual states per item
Every visual property of an item comes in three variants, which is the bulk of the API surface.
The state setters are grouped by property. Images first, and the requirement is that you provide one image per item for each of the three arrays:
let normalImages = Array(repeating: UIImage(named: "arrow_nor"), count: 4)
let selectedImages = Array(repeating: UIImage(named: "arrow_sel"), count: 4)
let disabledImages = Array(repeating: UIImage(named: "arrow_dim"), count: 4)
dropDownMenu.setStatesImages(
normalImages: normalImages,
selectedImages: selectedImages,
disabledImages: disabledImages
)Then colours, in one call:
dropDownMenu.setLabelColorWhen(normal: .black, selected: .blue, disabled: .gray)And fonts, which follow the same three-state pattern:
dropDownMenu.setLabelFontWhen(
normal: .systemFont(ofSize: 12),
selected: .boldSystemFont(ofSize: 12),
disabled: .systemFont(ofSize: 12)
)The disabled state is also a runtime state, not only a visual one, because an item can be disabled and re-enabled at runtime:
dropDownMenu.disabledMenu(at: 2)
dropDownMenu.enabledMenu(at: 3)That is a design decision worth noticing. A three-state design where the disabled state is only about appearance tends to produce menus where the item looks unavailable but still responds. Here the disabled flag is part of the item's state, and the two methods are the way to change it.
One more element is outside the three-state scheme, and it is the underline at the bottom of the bar, which is exposed as a view rather than as a property:
dropDownMenu.bottomLine.backgroundColor = .black
dropDownMenu.bottomLine.isHidden = falseThe background is a blur effect you can replace
The area behind the open dropdown is a blur, and the README shows the whole configuration surface for it.
// Enadbled or Disabled first (Default true)
dropDownMenu.backgroundBlurEnabled = false
// Use this line if you want to change UIBlurEffectStyle
dropDownMenu.blurEffectStyle = .light
// Or customize blurEffectView(UIView)
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.black
dropDownMenu.blurEffectView = backgroundView
// Animation end alpha
dropDownMenu.blurEffectViewAlpha = 0.7The blur is enabled by default, and the style is a `UIBlurEffectStyle`. The third case is the interesting one: `blurEffectView` is a `UIView` property, so you can replace the blur with any view, including a plain coloured view, and the alpha property controls how the background ends up looking once the animation finishes.
The animation itself is spring based, and the parameters are exposed in two groups, for showing and for hiding:
dropDownMenu.showMenuDuration = 0.5
dropDownMenu.hideMenuDuration = 0.3
dropDownMenu.showMenuSpringVelocity = 0.5
dropDownMenu.showMenuSpringWithDamping = 0.8
dropDownMenu.hideMenuSpringVelocity = 0.9
dropDownMenu.hideMenuSpringWithDamping = 0.8The durations and the spring parameters are separate, which is a slightly unusual split, since a spring animation has its own duration implied by its damping and velocity. It does mean the appearance animation and the disappearance animation can be tuned independently, which is what a designer usually wants for a menu.
For a control that has to match an existing application's motion, exposing velocity and damping rather than a single duration is the right call.
Where YNDropDownMenu is the wrong choice
The first wrong case is a SwiftUI application. Everything in the API is UIKit: `CGRect` frames, `UIView` arrays, `UIImage`, `UIColor`, `UIFont` and `UIBlurEffectStyle`. There is no SwiftUI wrapper described in the README, and adding one is a project of its own.
The second is a menu whose content is dynamic. The control holds an array of views built at initialisation time, and changing a title means calling `changeMenu(title:at:)` and changing a view means calling `changeView(view:at:)`. For a list that comes from a server, or a set of options that changes while the menu is open, you are mutating the control's internals from the outside rather than giving it a data source, and the array and the titles have to be kept in step by hand.
The third is a team that wants a maintained component. The release history has a seven year gap, and the reason for the jump was a Swift 6 modernisation, which means the 3.x line and the 4.x line differ in more than version numbering. The README's own Deprecated section is evidence of an API that is being reshaped, and the presence of old method names kept only for source compatibility is a signal that a future version may drop them.
The fourth is a project that has standardised on a menu component. If the application already uses a design system with its own dropdown, a second one adds a dependency, a second visual language and a second set of layout conventions, for a control that does exactly one thing.
The fifth is a menu with many items. The control lays out a row of titles in a bar, and the README does not describe scrolling, overflow or a title that does not fit, so a wide set of options is a case the library does not appear to address.
Editorial conclusion
Adopt YNDropDownMenu if you are building a UIKit iOS application and want a dropdown whose content is a view you control rather than a table view the control owns, and you are on iOS 13 or later with a Swift 6 toolchain. Do not adopt it for a SwiftUI project, since there is no SwiftUI interface described, and do not adopt it if you need an actively maintained component, because the version history jumps from 3.1.0 in 2019 to 4.0.0 in 2026. Before you integrate, note that the 3.x style method names still exist for source compatibility, so use the replacements such as `alwaysSelected(at:)` and `showAndHideMenu(at:)` from the start rather than porting later.
Frequently asked questions
How do I add YNDropDownMenu to an Xcode project?
Through Swift Package Manager, by choosing File then Add Package Dependencies and entering the repository URL, or by adding `.package(url: "https://github.com/younatics/YNDropDownMenu.git", from: "4.0.0")` to Package.swift. It is also on CocoaPods as `pod 'YNDropDownMenu', '~> 4.0.0'`.
What are the minimum requirements for YNDropDownMenu?
The README states that it is written in Swift 6.0 and requires iOS 13.0 or later, that the package manifest uses Swift tools 6.0, and that the CocoaPods deployment target is iOS 13.0.
How do I change the title or the content of a dropdown item?
From a YNDropDownView subclass you can call `changeMenu(title:at:)`, `changeMenu(title:status:at:)` and `changeView(view:at:)`, and you can move an item between states with `alwaysSelected(at:)` and `normalSelected(at:)`.
Can I disable a single item in the menu?
Yes. `disabledMenu(at:)` disables an item and `enabledMenu(at:)` re-enables it, and the item also has distinct images, colours and fonts for the normal, selected and disabled states.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/younatics-yndropdownmenu)Was this useful?