HorizonCalendar
A declarative, performant, iOS calendar UI component that supports use cases ranging from simple date pickers all the way up to fully-featured calendar apps.
Install / Use
/learn @airbnb/HorizonCalendarREADME
HorizonCalendar
A declarative and performant calendar UI component that supports use cases ranging from simple date pickers all the way up to fully-featured calendar apps.
Introduction
HorizonCalendar is a declarative and performant calendar UI component for iOS. It provides many customization points to support a diverse range of designs and use cases, and is used used to implement every calendar and date picker in the Airbnb iOS app.
Features:
- SwiftUI and UIKit support
- Vertical and horizontal month layouts
- Paging for horizontal month layout
- Right-to-left layout support
- Declarative API that encourages unidirectional data flow for updating the content of the calendar
- Supports displaying large (virtually-infinite) date ranges
- Animated content updates
- Customizable default views for days, month headers, and days of the week, and a month grid background
- Specify custom views for individual days, month headers, and days of the week
- Specify custom views to highlight date ranges
- Specify custom views to overlay parts of the calendar, enabling features like tooltips
- Specify custom views for month background decorations (colors, grids, etc.)
- Specify custom views for day background decorations (colors, patterns, etc.)
- A day selection handler to monitor when a day is tapped
- A multi-day selection handler to monitor when multiple days are selected via a drag gesture
- Customizable layout metrics
- Pin the days-of-the-week row to the top
- Show partial boundary months (exactly 2020-03-14 to 2020-04-20, for example)
- Scroll to arbitrary dates and months, with or without animation
- Robust accessibility support
- Inset the content without affecting the scrollable region using layout margins
- Separator below the days-of-the-week row
- Supports all calendars from
Foundation.Calendar(Gregorian, Japanese, Hebrew, etc.)
| Search | Stays Availability Calendar | Wish List | Experience Reservation | Experience Host Calendar Management |
| --- | --- | --- | --- | --- |
|
|
|
|
|
|
Table of Contents
- Example App
- Integration Tutorial
- Testing
- Technical Details
- Contributions
- Authors
- Maintainers
- License
Example App
An example app is available to showcase and enable you to test some of HorizonCalendar's features. It can be found in ./Example/HorizonCalendarExample.xcworkspace.
Note: Make sure to use the .xcworkspace file, and not the .xcodeproj file, as the latter does not have access to HorizonCalendar.framework.
Demos
The example app has several demo view controllers to try, with both vertical and horizontal layout variations:

Single Day Selection
| Vertical | Horizontal |
| ---- | ---- |
|
|
|
Day Range Selection
| Vertical | Horizontal |
| ---- | ---- |
|
|
|
Selected Day Tooltip
| Vertical | Horizontal |
| ---- | ---- |
|
|
|
Scroll to Day with Animation
| Vertical | Horizontal |
| ---- | ---- |
|
|
|
Integration Tutorial
Requirements
- Deployment target iOS 11.0+
- Swift 5+
- Xcode 10.2+
Installation
Swift Package Manager
To install HorizonCalendar using Swift Package Manager, add
.package(name: "HorizonCalendar", url: "https://github.com/airbnb/HorizonCalendar.git", from: "1.0.0")," to your Package.swift, then follow the integration tutorial here.
Carthage
To install HorizonCalendar using Carthage, add
github "airbnb/HorizonCalendar" to your Cartfile, then follow the integration tutorial here.
CocoaPods
To install HorizonCalendar using CocoaPods, add
pod 'HorizonCalendar' to your Podfile, then follow the integration tutorial here.
Creating a calendar
Once you've installed HorizonCalendar into your project, getting a basic calendar working is just a few steps.
Basic Setup
Importing HorizonCalendar
At the top of the file where you'd like to use HorizonCalendar, import HorizonCalendar:
import HorizonCalendar
Instantiating the view
<details> <summary>SwiftUI</summary>CalendarViewRepresentable is the SwiftUI view type that represents the calendar. Like other SwiftUI views, all customization is done through initializer parameters and modifiers. To create a basic calendar, you initialize a CalendarViewRepresentable with some initial data:
let calendar = Calendar.current
let startDate = calendar.date(from: DateComponents(year: 2020, month: 01, day: 01))!
let endDate = calendar.date(from: DateComponents(year: 2021, month: 12, day: 31))!
CalendarViewRepresentable(
calendar: calendar,
visibleDateRange: startDate...endDate,
monthsLayout: .vertical(options: VerticalMonthsLayoutOptions()),
dataDependency: nil)
</details>
<details>
<summary>UIKit</summary>
CalendarView is the UIView subclass that renders the calendar. All visual aspects of CalendarView are controlled through a single type - CalendarViewContent. To create a basic CalendarView, you initialize one with an initial CalendarViewContent:
let calendarView = CalendarView(initialContent: makeContent())
private func makeContent() -> CalendarViewContent {
let calendar = Calendar.current
let startDate = calendar.date(from: DateComponents(year: 2020, month: 01, day: 01))!
let endDate = calendar.date(from: DateComponents(year: 2021, month: 12, day: 31))!
return CalendarViewContent(
calendar: calendar,
visibleDateRange: startDate...endDate,
monthsLayout: .vertical(options: VerticalMonthsLayoutOptions()))
}
At a minimum, CalendarViewContent must be initialized with a Calendar, a visible date range, and a months layout (either vertical or horizontal). The visible date range will be interpreted as a range of days using the Calendar instance passed in for the calendar parameter.
For this example, we're using a Gregorian calendar, a date range of 2020-01-01 to 2021-12-31, and a vertical months layout.
Make sure to add calendarView as a subview, then give it a valid frame either using Auto Layout or by manually setting its frame property. If you're using Auto Layout, note that CalendarView does not have an intrinsic content size.
view.addSubview(calendarView)
calendarView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
calendarView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor),
calendarView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor),
calendarVie
Related Skills
openhue
350.1kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
350.1kElevenLabs text-to-speech with mac-style say UX.
weather
350.1kGet current weather and forecasts via wttr.in or Open-Meteo
casdoor
13.3kAn open-source AI-first Identity and Access Management (IAM) /AI MCP & agent gateway and auth server with web UI supporting OpenClaw, MCP, OAuth, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA, Face ID, Google Workspace, Azure AD
