Skip to content

Previews in Xcode (SwiftUI)

A SwiftUI guide for coding agents. Also covers previewable macro, preview binding state, previewmodifier protocol, mock data preview, preview traits modifier, xcode preview environment.

Xcode 16 removed the boilerplate around previews. @Previewable inlines state into the #Preview macro, and PreviewModifier builds a reusable, cached preview environment such as a mock data container.

Inline state with @Previewable

A view with a @Binding used to need a wrapper view whose only job was to own the @State. @Previewable declares that state inside the #Preview block instead. Using it outside #Preview is a compiler error.

#Preview {
  @Previewable @State var goal: TimeInterval = 8 * 3600

  SleepDetailsView(snapshot: SleepSnapshot(), goal: $goal)
    .preferredColorScheme(.dark)
}

@Previewable works with other SwiftUI property wrappers too, such as @Environment and SwiftData's @Query.

Reusable environments with PreviewModifier

A PreviewModifier has two requirements. makeSharedContext builds whatever the preview needs, for example an in-memory ModelContainer filled with mock data. body(content:context:) applies that context to the previewed view, through modelContainer here, or through environment for a custom store.

struct MockDataPreviewModifier: PreviewModifier {
  static func makeSharedContext() throws -> ModelContainer {
    let container = try ModelContainer(
      for: Item.self,
      configurations: ModelConfiguration(isStoredInMemoryOnly: true)
    )
    populateContainer(container)
    return container
  }

  func body(content: Content, context: ModelContainer) -> some View {
    content.modelContainer(context)
  }
}

Apply it through the traits parameter:

#Preview(traits: .modifier(MockDataPreviewModifier())) {
  ItemsView()
}

The shared context is cached

Xcode caches the value returned by makeSharedContext and reuses it across every preview with the same trait. Expensive setup, such as seeding a data container, runs once instead of once per preview.

Use this guidance in your coding agent

Install the Better Design MCP once. Your agent then loads this page with one call.

get-swiftui-guide({ topic: "swiftui-the-power-of-previews-in-xcode" })
claude mcp add --scope user better-design --transport http https://better-design.com/api/mcp --header "Authorization: Bearer <YOUR_API_KEY>"
Browse related design systems