Epoxy is a suite of declarative UI APIs for building UIKit applications in Swift. Epoxy is inspired and influenced by the wonderful Epoxy framework on Android, as well as other declarative UI frameworks in Swift such as SwiftUI.
Epoxy was developed at Airbnb and powers thousands of screens in apps that are shipped to millions of users. It has been developed and refined for years by dozens of contributors.
Below are a few sample screens from the Airbnb app that we’ve built using Epoxy. Our usages of Epoxy span from our simplest forms and static screens to our most advanced and dynamic features.
| Home Details | Home Photos | Messaging | Registration |
| — | — | — | — |
| | | | |
There’s also a full sample app with a lot of examples that you can either run via the EpoxyExample scheme in Epoxy.xcworkspace or browse its source.
If you still have questions, feel free to create a new issue.
Getting started
EpoxyCollectionView
EpoxyCollectionView provides a declarative API for driving the content of a UICollectionView. CollectionViewController is a subclassable UIViewController that lets you easily spin up a UICollectionView-backed view controller with a declarative API.
The following code samples will render a single cell in a UICollectionView with a TextRow component rendered in that cell. TextRow is a simple UIView containing two labels that conforms to the EpoxyableView protocol.
You can either instantiate a CollectionViewController instance directly with sections, e.g. this view controller with a selectable row:
EpoxyBars provides a declarative API for rendering fixed top, fixed bottom, or input accessory bar stacks in a UIViewController.
The following code example will render a ButtonRow component fixed to the bottom of the UIViewController‘s view. ButtonRow is a simple UIView component that contains a single UIButton constrained to the margins of the superview that conforms to the EpoxyableView protocol:
LayoutGroups are UIKit Auto Layout containers inspired by SwiftUI’s HStack and VStack that allow you to easily compose UIKit elements into horizontal and vertical groups.
VGroup allows you to group components together vertically to create stacked components like this:
Source
Result
// Set of dataIDs to have consistent
// and unique IDs
enum DataID {
case title
case subtitle
case action
}
// Groups are created declaratively
// just like Epoxy ItemModels
let group = VGroup(
alignment: .leading,
spacing: 8)
{
Label.groupItem(
dataID: DataID.title,
content: "Title text",
style: .title)
Label.groupItem(
dataID: DataID.subtitle,
content: "Subtitle text",
style: .subtitle)
Button.groupItem(
dataID: DataID.action,
content: "Perform action",
behaviors: .init { button in
print("Button tapped! \(button)")
},
style: .standard)
}
// install your group in a view
group.install(in: view)
// constrain the group like you
// would a normal subview
group.constrainToMargins()
As you can see, this is incredibly similar to the other APIs used in Epoxy. One important thing to note is that install(in: view) call at the bottom. Both HGroup and VGroup are written using UILayoutGuide which prevents having large nested view hierarchies. To account for this, we’ve added this install method to prevent the user from having to add subviews and the layout guide manually.
Using HGroup is almost exactly the same as VGroup but the components are now horizontally laid out instead of vertically:
Source
Result
enum DataID {
case icon
case title
}
let group = HGroup(spacing: 8) {
ImageView.groupItem(
dataID: DataID.icon,
content: UIImage(systemName: "person.fill")!,
style: .init(size: .init(width: 24, height: 24)))
Label.groupItem(
dataID: DataID.title,
content: "This is an IconRow")
}
group.install(in: view)
group.constrainToMargins()
Groups support nesting too, so you can easily create complex layouts with multiple groups:
Source
Result
enum DataID {
case checkbox
case titleSubtitleGroup
case title
case subtitle
}
HGroup(spacing: 8) {
Checkbox.groupItem(
dataID: DataID.checkbox,
content: .init(isChecked: true),
style: .standard)
VGroupItem(
dataID: DataID.titleSubtitleGroup,
style: .init(spacing: 4))
{
Label.groupItem(
dataID: DataID.title,
content: "Build iOS App",
style: .title)
Label.groupItem(
dataID: DataID.subtitle,
content: "Use EpoxyLayoutGroups",
style: .subtitle)
}
}
Pull requests are welcome! We’d love help improving this library. Feel free to browse through open issues to look for things that need work. If you have a feature request or bug, please open a new issue so we can track it. Contributors are expected to follow the Code of Conduct.
License
Epoxy is released under the Apache License 2.0. See LICENSE for details.
Epoxy is a suite of declarative UI APIs for building UIKit applications in Swift. Epoxy is inspired and influenced by the wonderful Epoxy framework on Android, as well as other declarative UI frameworks in Swift such as SwiftUI.
Epoxy was developed at Airbnb and powers thousands of screens in apps that are shipped to millions of users. It has been developed and refined for years by dozens of contributors.
Below are a few sample screens from the Airbnb app that we’ve built using Epoxy. Our usages of Epoxy span from our simplest forms and static screens to our most advanced and dynamic features. | Home Details | Home Photos | Messaging | Registration | | — | — | — | — | |
|
|
|
|
Table of contents
Installation
Epoxy can be installed using CocoaPods or Swift Package Manager.
CocoaPods
To get started with Epoxy using Cocoapods add the following to your
Podfile
and then follow the integration instructions.Epoxy is separated into podspecs for each module so you only have to include what you need.
Swift Package Manager (SPM)
To install Epoxy using Swift Package Manager you can follow the tutorial published by Apple using the URL for the Epoxy repo with the current version:
Epoxy is separated library products for each module so you only have to include what you need.
Modules
Epoxy has a modular architecture so you only have to include what you need for your use case:
Epoxy
EpoxyCollectionView
UICollectionView
EpoxyNavigationController
UINavigationController
EpoxyPresentations
UIViewController
EpoxyBars
UIViewController
EpoxyLayoutGroups
EpoxyCore
Documentation and tutorials
For full documentation and step-by-step tutorials please check the wiki. For type-level documentation, see the Epoxy DocC documentation hosted on the Swift Package Index.
There’s also a full sample app with a lot of examples that you can either run via the
EpoxyExample
scheme inEpoxy.xcworkspace
or browse its source.If you still have questions, feel free to create a new issue.
Getting started
EpoxyCollectionView
EpoxyCollectionView
provides a declarative API for driving the content of aUICollectionView
.CollectionViewController
is a subclassableUIViewController
that lets you easily spin up aUICollectionView
-backed view controller with a declarative API.The following code samples will render a single cell in a
UICollectionView
with aTextRow
component rendered in that cell.TextRow
is a simpleUIView
containing two labels that conforms to theEpoxyableView
protocol.You can either instantiate a
CollectionViewController
instance directly with sections, e.g. this view controller with a selectable row:Or you can subclass
CollectionViewController
for more advanced scenarios, e.g. this view controller that keeps track of a running count:You can learn more about
EpoxyCollectionView
in its wiki entry, or by browsing the code documentation.EpoxyBars
EpoxyBars
provides a declarative API for rendering fixed top, fixed bottom, or input accessory bar stacks in aUIViewController
.The following code example will render a
ButtonRow
component fixed to the bottom of theUIViewController
‘s view.ButtonRow
is a simpleUIView
component that contains a singleUIButton
constrained to the margins of the superview that conforms to theEpoxyableView
protocol:You can learn more about
EpoxyBars
in its wiki entry, or by browsing the code documentation.EpoxyNavigationController
EpoxyNavigationController
provides a declarative API for driving the navigation stack of aUINavigationController
.The following code example shows how you can use this to easily drive a feature that has a flow of multiple view controllers:
You can learn more about
EpoxyNavigationController
in its wiki entry, or by browsing the code documentation.EpoxyPresentations
EpoxyPresentations
provides a declarative API for driving the modal presentation of aUIViewController
.The following code example shows how you can use this to easily drive a feature that shows a modal when it first appears:
You can learn more about
EpoxyPresentations
in its wiki entry, or by browsing the code documentation.EpoxyLayoutGroups
LayoutGroups are UIKit Auto Layout containers inspired by SwiftUI’s
HStack
andVStack
that allow you to easily compose UIKit elements into horizontal and vertical groups.VGroup
allows you to group components together vertically to create stacked components like this:As you can see, this is incredibly similar to the other APIs used in Epoxy. One important thing to note is that
install(in: view)
call at the bottom. BothHGroup
andVGroup
are written usingUILayoutGuide
which prevents having large nested view hierarchies. To account for this, we’ve added thisinstall
method to prevent the user from having to add subviews and the layout guide manually.Using
HGroup
is almost exactly the same asVGroup
but the components are now horizontally laid out instead of vertically:Groups support nesting too, so you can easily create complex layouts with multiple groups:
You can learn more about
EpoxyLayoutGroups
in its wiki entry, or by browsing the code documentation.FAQ
Contributing
Pull requests are welcome! We’d love help improving this library. Feel free to browse through open issues to look for things that need work. If you have a feature request or bug, please open a new issue so we can track it. Contributors are expected to follow the Code of Conduct.
License
Epoxy is released under the Apache License 2.0. See
LICENSE
for details.Credits
Logo design by Alana Hanada and Jonard La Rosa