# YNDropDownMenu: a Swift 6 dropdown that shows whatever view you hand 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.

**younatics/YNDropDownMenu** — ✨ Awesome Dropdown menu for iOS with Swift 5.0

- Repository: https://github.com/younatics/YNDropDownMenu
- Website: https://www.cocoacontrols.com/controls/yndropdownmenu
- Stars: 1,326 · Forks: 113
- Language: Swift
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/younatics-yndropdownmenu

## 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:

```swift
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:

```swift
dependencies: [
    .package(url: "https://github.com/younatics/YNDropDownMenu.git", from: "4.0.0")
]
```

For CocoaPods, it is a line in the Podfile:

```ruby
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.

```swift
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:

```swift
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:

```swift
dropDownMenu.setLabelColorWhen(normal: .black, selected: .blue, disabled: .gray)
```

And fonts, which follow the same three-state pattern:

```swift
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:

```swift
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:

```swift
dropDownMenu.bottomLine.backgroundColor = .black
dropDownMenu.bottomLine.isHidden = false
```

## The 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.

```swift
// 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.7
```

The 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:

```swift
dropDownMenu.showMenuDuration = 0.5
dropDownMenu.hideMenuDuration = 0.3

dropDownMenu.showMenuSpringVelocity = 0.5
dropDownMenu.showMenuSpringWithDamping = 0.8

dropDownMenu.hideMenuSpringVelocity = 0.9
dropDownMenu.hideMenuSpringWithDamping = 0.8
```

The 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.

## 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.

## FAQ

### 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.

## Sources

- [License: MIT](https://github.com/younatics/YNDropDownMenu/blob/master/LICENSE)
- [Project website](https://www.cocoacontrols.com/controls/yndropdownmenu)
- [README](https://github.com/younatics/YNDropDownMenu/blob/master/README.md)
- [Releases](https://github.com/younatics/YNDropDownMenu/releases)
- [younatics/YNDropDownMenu on GitHub](https://github.com/younatics/YNDropDownMenu)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/younatics-yndropdownmenu
