TechnologiesSwiftUIPreviews and Layout Modifiers

PreviewDevice struct

iOSmacOStvOSwatchOSvisionOSiOS 13.0+✓ renders

A simulator device that runs a preview.

How it works

PreviewDevice identifies the hardware on which Xcode renders a SwiftUI preview, letting you see your view as it would appear on a particular iPhone, iPad, Apple Watch, or Mac without launching the simulator. By default a preview adopts the device currently selected in the canvas, but when you want to lock a preview to a known screen size, safe-area inset, or form factor, you create a PreviewDevice and hand it to the previewDevice(_:) modifier. Reach for it when a layout depends on a specific device's dimensions, or when you want several previews pinned to different devices side by side.

  1. Create the device with PreviewDevice(rawValue:)

    PreviewDevice is a lightweight value type whose entire identity is the device name you pass in. Construct one with its raw-value initializer, supplying the exact model string Xcode recognizes — here PreviewDevice(rawValue: "iPhone 15 Pro"). The string must match a destination Xcode knows about; an unrecognized name falls back to the canvas default.

  2. Conform via ExpressibleByStringLiteral and RawRepresentable

    Because PreviewDevice conforms to RawRepresentable with a String raw value and is ExpressibleByStringLiteral, you can often write the bare literal "iPhone 15 Pro" wherever a PreviewDevice is expected. The explicit PreviewDevice(rawValue:) form in the example spells out the same value and makes the device's identity obvious at the call site.

  3. Apply it with previewDevice(_:)

    A PreviewDevice has no effect on its own — it takes hold only when attached to a view through the previewDevice(_:) modifier. The example caps the view's modifier chain with .previewDevice(PreviewDevice(rawValue: "iPhone 15 Pro")), which tells the canvas to render that view's body using the named device's screen geometry and traits.

  4. Pin each preview to its own device

    The modifier applies to the view it's called on, so PreviewDevice scopes per preview rather than globally. Returning the same body from several previews, each ending in a different previewDevice(_:), gives you a gallery of one layout across many devices — useful for catching clipping or spacing that only shows up at a particular size.

Try it — Change the raw value in PreviewDevice(rawValue: "iPhone 15 Pro") to "iPad Pro 13-inch (M4)" and watch the same layout re-render at iPad dimensions in the canvas.

Example & preview

Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.

PreviewDevice.swift
struct PreviewDeviceDemo: View {
    var body: some View {
        VStack(spacing: 8) {
            Image(systemName: "iphone")
                .font(.largeTitle)
            Text("iPhone 15 Pro")
                .font(.headline)
            Text("Rendered for a specific PreviewDevice")
                .font(.caption)
                .foregroundColor(.secondary)
        }
        .padding()
        .previewDevice(PreviewDevice(rawValue: "iPhone 15 Pro"))
    }
}
Live preview
iPhone 15 Pro Rendered for a specific PreviewDevice
iPhone 15 Pro Rendered for a specific PreviewDevice
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →