The #Preview macro renders a view in the Xcode Preview Canvas with one closure, replacing the
PreviewProvider boilerplate. It also previews UIKit types and widget timelines.
The Basic Form
Wrap the view in the macro. Any modifier applies, so a dark-mode preview is one line.
#Preview {
ContentView()
.preferredColorScheme(.dark)
}
The macro is not SwiftUI-only. Return any UIViewController or UIView instance and the canvas
renders it too.
#Preview {
SearchViewController()
}
One Preview Per State
Declare several #Preview macros in one file to show different states side by side. Pass a title
string so the canvas can tell them apart.
#Preview("Empty state") {
ItemsView(data: .empty)
}
#Preview("Error state") {
ItemsView(data: .error)
}
A file can contain only previews. That works well as living documentation for a design system package: one file per component, one preview per state.
Traits: Orientation and Size
The traits parameter puts the preview in landscape or a fixed layout size. This overload is
iOS 17+, so it needs an availability attribute in code that targets earlier versions.
@available(iOS 17, *)
#Preview(traits: .landscapeLeft) {
ContentView()
}
@available(iOS 17, *)
#Preview(traits: .fixedLayout(width: 300, height: 300)) {
ContentView()
}
Sweep a Whole Axis
A wrapper view previews every variant of one environment axis at once, such as every Dynamic Type size.
struct SizeCategoryPreview<Content: View>: View {
let content: Content
var body: some View {
ForEach(ContentSizeCategory.allCases, id: \.self) { size in
content.environment(\.sizeCategory, size)
}
}
}
#Preview {
SizeCategoryPreview(content: ContentView())
}
Debugging a Preview
Previews run in an embedded simulator, so you can debug them: Debug menu, Attach to Process, pick the app, then use Debug View Hierarchy. Cmd+Option+Enter toggles the canvas and Cmd+Option+P runs the preview. Small, decomposed views keep previews fast and stable.
Widget Timelines
The as: overload previews a widget in a given family and plays an interactive timeline from the
provider you supply.
#Preview(as: .accessoryRectangular) {
SugarBotWidget()
} timeline: {
RawValuesProvider()
}