<!--
{
  "documentType" : "article",
  "framework" : "Xcode",
  "identifier" : "/documentation/Xcode/previewing-your-apps-interface-in-xcode",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Previewing your app’s interface in Xcode"
}
-->

# Previewing your app’s interface in Xcode

Iterate designs quickly and preview your apps’ displays across different Apple devices.

## Overview

With Swift previews, you can make changes to your app’s views in code, and see the result of those changes quickly in the preview canvas. Add previews to your SwiftUI, UIKit, and AppKit views using the preview macro. Then configure how you want your previews to display using the preview canvas controls, or programmatically in code.

### Add a preview macro to your interface file

When you add views to your code, you can display them in the preview canvas. The preview canvas shows how your view appears on different devices in a variety of configurations.

![A screenshot of Xcode with the Project navigator on the left, the code editor in the middle, and the preview canvas on the right.](images/com.apple.Xcode/dynamically-previewing-1-preview-macro@2x.png)

The Swift preview macro is a snippet of code that makes and configures your view. You use one of the preview macros — such as <doc://com.apple.documentation/documentation/SwiftUI/Preview(_:body:)> — to tell Xcode what to display. To manually show or hide the preview canvas, select Editor > Canvas from the Xcode menu.

**SwiftUI:**

```swift
// A SwiftUI preview.
#Preview {
    // The view to preview.
}
```

**UIKit:**

```swift
// A UIKit preview.
#Preview {
    // The view or view controller to preview.
}
```

**AppKit:**

```swift
// An AppKit preview.
#Preview {
    // The view or view controller to preview.
}
```

To add a preview macro to your view:

1. Open the source file of the view you want to display.
2. Add the `#Preview` macro to the file.
3. Create and return an instance of the view configuration you want to display in the body of the trailing closure of the macro.

**SwiftUI:**

```swift
struct ContentView: View {
    var body: some View {
        // ...
    }
}

// A SwiftUI preview.
#Preview {
    ContentView()
}
```

**UIKit:**

```swift
class WeatherViewController: UIViewController {
    // ...
}

// A UIKit UIViewController preview.
#Preview {
    let viewController = WeatherViewController()
    viewController.title = "Current Weather"
    return viewController
}

class WeatherView: UIView {
    var icon: UIImage?
}

// A UIKit UIView preview.
#Preview {
    let view = WeatherView()
    if let image = UIImage(systemName: "sun.max.fill") {
        view.icon = image
    }
    return view
}
```

**AppKit:**

```swift
class WeatherViewController: NSViewController {
    // ...
}

// An AppKit NSViewController preview.
#Preview {
    let viewController = WeatherViewController()
    viewController.title = "Current Weather"
    return viewController
}

class WeatherView: NSView {
    var icon: NSImage?
}

// An AppKit NSView preview.
#Preview {
    let view = WeatherView()
    view.icon = NSImage(symbolName: "sun.max.fill", variableValue: 0.0)
    return view
}
```

### Generate previews using intelligence

You can use Xcode coding intelligence to generate a preview for you. In the source editor, select some view code and click the coding assistant icon that appears, or Control-click a symbol and choose Show Coding Tools > Show Coding Tools from the pop-up menu. In the coding tools popover that appears, click Generate a Preview.

For more information on coding intelligence features, see [Writing code with intelligence in Xcode](/documentation/Xcode/writing-code-with-intelligence-in-xcode).

### Interact with your view in live mode

When you select the live or interactive preview option, your view appears and interacts just like it would on a device or simulator. Use live mode to test control logic, animations, and text entry as well as responses to asynchronous code. When you click the Live button at the bottom of the preview canvas, a single device preview appears in the canvas that you can interact with. This is the default mode for new previews that you add to your files.

### Try out new designs quickly with selectable mode

In selectable mode, the preview displays a snapshot of your view so you can interact with your view’s UI elements in the canvas. To highlight the code for an element in the source editor, click the Selectable button at the bottom of the preview canvas, and double-click the element in the preview canvas. Xcode highlights both the element in the preview canvas and the corresponding code in the source editor. Then you can make code changes to the element in the source editor and see the results immediately in the preview canvas.

![A screenshot of Xcode with the code editor in the middle, and a preview on the right. The selectable mode button at the bottom of the preview canvas is active. The preview canvas displays a preview of the view in the selectable mode.](images/com.apple.Xcode/dynamically-previewing-3-select-mode@2x.png)

### Control how your previews display with device settings

Use Device settings to control how a preview displays for a specific device. For example, to see how your view looks in the dark appearance, in a landscape right orientation, with extra large text:

1. Click Device Settings at the bottom of the preview canvas.
2. Toggle Color Scheme on, and select Dark Appearance under Color Scheme.
3. Toggle Orientation on, and select Landscape Right under Orientation.
4. Toggle Dynamic Type on, and move the Dynamic Type slider to the X Large text setting.

![A screenshot of the Canvas Device Settings dialog showing the Color Scheme, Orientation, and Dynamic Type switches and controls.](images/com.apple.Xcode/dynamically-previewing-6-device-settings@2x.png)

### Test different view configurations

Use variant mode to see how your view appears in different variations for a given configuration. For example, to test how well your view supports accessibility, select Variant mode from the bottom of the preview canvas, and select the Dynamic Type Variants option. Xcode displays your view with different sizes of text.

![A screenshot of the preview canvas. The variant mode button at the bottom of the preview canvas is active. The preview canvas displays a preview of the view for each variant of Dynamic Type size. Six previews are visible, each displaying the view with a different size of text.](images/com.apple.Xcode/dynamically-previewing-4-variant-mode@2x.png)

Preview canvas supports the following variations:

- Color Scheme Variants: Displays a light and dark preview of your view.
- Orientation Variants: Displays your view in all the different portrait and landscape orientations.
- Dynamic Type Variants: Displays your view in all the accessibility text sizes for your app.

> Experiment: Because variant mode shows all the values for a given device setting, you can override what variant mode displays by making further changes in Canvas Device Settings. For example, to see how your view appears in different sizes of text in dark appearance, toggle Dynamic Type on, toggle Color Scheme on, and select Dark Appearance under Color Scheme.

### Preview on a specific device

To see how your view displays on a specific device, choose the device from the Preview Device pop-up menu at the bottom of the preview canvas. When you do, Xcode displays a preview of your view on that device.

![A screenshot of the preview canvas. The preview destination mode button at the bottom of the preview canvas is active, set to iPad. The preview canvas displays a preview of the view on an iPad.](images/com.apple.Xcode/dynamically-previewing-5-preview-destination@2x.png)

### Capture specific previews in code

In addition to the preview options Xcode provides, you can also customize and configure previews you want to reuse programmatically.

For example, you can add a name to more easily track what each preview displays. When you pass the name of your preview as a string into the preview macro, the name appears in the title of the preview in the preview canvas.

```swift
// A preview with an assigned name.
#Preview("2x2 Grid Portrait") {
   Content()
}
```

> Note: If you add multiple preview and playground macros to a file, you can switch between them using the
> tabs that appear at the top of the canvas. Xcode uses the name that you pass to the macro as the label for that preview. To add playgrounds to your Swift code, see <doc://com.apple.Xcode/documentation/Xcode/running-code-snippets-using-the-playground-macro>.

You can also control how your preview displays by passing one or more configuration traits as a variadic argument list into the preview macro. For example, to display your view in the landscape left orientation, pass the <doc://com.apple.documentation/documentation/DeveloperToolsSupport/PreviewTrait/landscapeLeft> type property into the  <doc://com.apple.documentation/documentation/DeveloperToolsSupport/Preview/init(_:traits:body:)-8pemr> preview initializer to tell Xcode which orientation to display.

**SwiftUI:**

```swift
// A SwiftUI preview with name and orientation.
#Preview("2x2 grid", traits: .landscapeLeft) {
    CollageView(layout: .twoByTwoGrid)
}
```

**UIKit:**

```swift
// A UIKit preview with name and orientation.
#Preview("Camera setting sunning day", traits: .landscapeLeft) {
    let viewController = CameraViewController()
    if let image = UIImage(systemName: "sun.max.fill") {
        viewController.lastImage = image
    }
    return viewController
}
```

**AppKit:**

```swift
// An AppKit preview with name and orientation.
#Preview("Camera setting sunning day", traits: .landscapeLeft) {
    let viewController = CameraViewController()
    viewController.lastImage = NSImage(symbolName: "sun.max.fill", variableValue: 0.0)
    return viewController
}
```

### Use inline dynamic properties with Previewable

When a view depends on a <doc://com.apple.documentation/documentation/SwiftUI/Binding> property wrapper, you can create a functional binding for that property and pass it into your preview using the <doc://com.apple.documentation/documentation/SwiftUI/Previewable()> macro. This macro works on any variable conforming to the <doc://com.apple.documentation/documentation/SwiftUI/DynamicProperty> protocol.

```swift
struct PlayButton: View {
    @Binding var isPlaying: Bool

    var body: some View {
        Button(action: {
            self.isPlaying.toggle()
        }) {
            Image(systemName: isPlaying ? "pause.circle" : "play.circle")
            .resizable()
            .scaledToFit()
            .frame(maxWidth: 80)
        }
    }
}

#Preview {
    // Tag the dynamic property with `Previewable`.
    @Previewable @State var isPlaying = true

    // Pass it into your view.
    PlayButton(isPlaying: $isPlaying)
}
```

Tagging a dynamic property with the `Previewable` macro gets rid of the need to create wrapper views in previews.

> Note: <doc://com.apple.documentation/documentation/SwiftUI/Previewable()> is a SwiftUI only macro and doesn’t apply to UIKit or AppKit previews.

### Make complex objects reusable with a preview modifier

To avoid recreating expensive objects for every preview that needs them, in SwiftUI you can create these objects once with the <doc://com.apple.documentation/documentation/SwiftUI/PreviewModifier> and then pass the preview modifier into your preview using the <doc://com.apple.documentation/documentation/SwiftUI/Preview(_:traits:_:body:)> macro.

Expensive objects — such as objects that make network calls, perform disk access, or just take considerable time and effort to setup — can make your previews take longer to load. By creating these expensive objects once, and sharing them across all your previews, you make your previews more efficient.

For example, if you have an app with an expensive <doc://com.apple.documentation/documentation/Observation/Observable()> object:

```swift
@Observable
class AppState {
    // An expensive, complex, bulky object.
    var expensiveObject = "Some expensive object"
}

@main
struct MyApp: App {
    @State private var appState = AppState()

    var body: some Scene {
        WindowGroup {
            ComplexView()
                .environment(appState)
        }
    }
}
```

You reuse that expensive object across multiple views in your app:

```swift
struct ComplexView: View {
    @Environment(AppState.self) var appState

    var body: some View {
        Text("\(appState.expensiveObject)")
    }
}
```

For every view you want to preview, you recreate and pass in that expensive object:

```swift
#Preview {
    ComplexView()
        // Potentially expensive if `AppState` is large or complex.
        .environment(AppState())
}
```

Instead, define the expensive object once and share it across multiple previews using the <doc://com.apple.documentation/documentation/SwiftUI/PreviewModifier> protocol.

1. Define a structure conforming to the `PreviewModifier` protocol.
2. Implement the static <doc://com.apple.documentation/documentation/SwiftUI/PreviewModifier/makeSharedContext()-4zi8r> function returning the object with the expensive state.
3. Inject that shared context into the view you want to preview using the <doc://com.apple.documentation/documentation/SwiftUI/PreviewModifier/body(content:context:)> function.
4. Add the modifier to the preview using the <doc://com.apple.documentation/documentation/SwiftUI/Preview(_:traits:_:body:)> macro.

```swift
// Create a struct conforming to the PreviewModifier protocol.
struct SampleData: PreviewModifier {

    // Define the object to share and return it as a shared context.
    static func makeSharedContext() async throws -> AppState {
        let appState = AppState()
        appState.expensiveObject = "An expensive object to reuse in previews"
        return appState
    }

    func body(content: Content, context: AppState) -> some View {
        // Inject the object into the view to preview.
        content
            .environment(context)
    }
}

// Add the modifier to the preview.
#Preview(traits: .modifier(SampleData())) {
    ComplexView()
}
```

### Pass views only the data they need

When creating views, pass in only the data the view needs to display. Avoid passing in objects that fetch data; objects make setting up a view’s preview more complicated and less performant.

Instead, create views with the minimal amount of data they need, favoring simpler, immutable data types. Creating views this way makes testing and previewing your views easier and helps them perform better.

The following example shows how simple data types, like `String` and `enum`, can be used to preview a view in various ways using the preview macro.

**SwiftUI:**

```swift
struct CollaboratorCell: View {
    // Construct your view with only the data it needs.
    let name: String
    let image: Image?
    let connectionStatus: ConnectionStatus
    
    enum ConnectionStatus {
        case online
        case offline
    }

    // ...
}

#Preview("Supported cell combinations", traits: .sizeThatFitsLayout) {
    let image = Image(systemName: "person.circle")
    VStack {
        // Then test each scenario in your preview macro.
        CollaboratorCell(name: "Tom Clark", image: nil, connectionStatus: .offline)
        CollaboratorCell(name: "Tom Clark", image: image, connectionStatus: .offline)
        CollaboratorCell(name: "Tom Clark", image: nil, connectionStatus: .online)
        CollaboratorCell(name: "Tom Clark", image: image, connectionStatus: .online)
        CollaboratorCell(name: "Tom Long Middle Clark", image: nil, connectionStatus: .offline)
        CollaboratorCell(name: "Tom Long Middle Clark", image: image, connectionStatus: .online)
    }
}
```

**UIKit:**

```swift
class CollaboratorCell: UIView {
    // Construct your view with only the data it needs.
    let name: String
    let image: UIImage?
    let connectionStatus: ConnectionStatus
    
    enum ConnectionStatus {
        case online
        case offline
    }
    
    // ...
}

#Preview("Supported cell combinations", traits: .sizeThatFitsLayout) {
    let image = UIImage(systemName: "person.circle")
    
    // Then test each scenario in your preview macro.
    let cell1 = CollaboratorCell(name: "Tom Clark", image: nil, connectionStatus: .offline)
    let cell2 = CollaboratorCell(name: "Tom Clark", image: image, connectionStatus: .offline)
    let cell3 = CollaboratorCell(name: "Tom Clark", image: nil, connectionStatus: .online)
    let cell4 = CollaboratorCell(name: "Tom Clark", image: image, connectionStatus: .online)
    let cell5 = CollaboratorCell(name: "Tom Long Middle Clark", image: nil, connectionStatus: .offline)
    let cell6 = CollaboratorCell(name: "Tom Long Middle Clark", image: image, connectionStatus: .online)
    
    // Create a test harness to display.
    let stackView = UIStackView()
    stackView.axis = .vertical
    stackView.spacing = 8.0

    stackView.addArrangedSubview(cell1)
    stackView.addArrangedSubview(cell2)
    stackView.addArrangedSubview(cell3)
    stackView.addArrangedSubview(cell4)
    stackView.addArrangedSubview(cell5)
    stackView.addArrangedSubview(cell6)

    return stackView
}
```

**AppKit:**

```swift
class CollaboratorCell: NSView {
    // Construct your view with only the data it needs.
    let name: String
    let image: NSImage?
    let connectionStatus: ConnectionStatus

    enum ConnectionStatus {
        case online
        case offline
    }

    // ...
}

#Preview("Supported cell combinations", traits: .sizeThatFitsLayout) {
    let image = NSImage(systemSymbolName: "person.circle", accessibilityDescription: "A person symbol inside the outline of a circle.")

    // Then test each scenario in your preview macro.
    let cell1 = CollaboratorCell(name: "Tom Clark", image: nil, connectionStatus: .offline)
    let cell2 = CollaboratorCell(name: "Tom Clark", image: image, connectionStatus: .offline)
    let cell3 = CollaboratorCell(name: "Tom Clark", image: nil, connectionStatus: .online)
    let cell4 = CollaboratorCell(name: "Tom Clark", image: image, connectionStatus: .online)
    let cell5 = CollaboratorCell(name: "Tom Long Middle Clark", image: nil, connectionStatus: .offline)
    let cell6 = CollaboratorCell(name: "Tom Long Middle Clark", image: image, connectionStatus: .online)

    // Create a test harness to display.
    let stackView = NSStackView()
    stackView.orientation = .vertical
    stackView.spacing = 8.0

    stackView.addArrangedSubview(cell1)
    stackView.addArrangedSubview(cell2)
    stackView.addArrangedSubview(cell3)
    stackView.addArrangedSubview(cell4)
    stackView.addArrangedSubview(cell5)
    stackView.addArrangedSubview(cell6)

    return stackView
}
```

![A screenshot of the preview canvas displaying six previews of a data row view in various test scenario configurations. The preview canvas displays view variations for online and offline status, with and without an avatar image, and long and short display names.](images/com.apple.Xcode/dynamically-previewing-7-minimal-data@2x.png)

### Reduce your app size with development assets

To access resources in your previews, without shipping them in the final version of your app, use development assets. Development assets give you access to resources such as images, video, JSON data, and code files in your previews and Simulator, without increasing the overall size of your app.

Add items to the Development Assets of a project target as follows:

1. Select the project folder in the Project navigator.
2. Select the target you want to add the development assets to.
3. In the General tab, scroll down to Development Assets.
4. In the lower-left corner, click the Add items button (+).
5. In the dialog that appears, select the items that you want to add and click Add.

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)