← All release notes
SwiftUIiOS 18Aug 23, 2026 · 5 min read

What's New in SwiftUI — iOS 18

iOS 18 gives SwiftUI two macros that remove real boilerplate, a rebuilt TabView, zoom transitions, and MeshGradient.

iOS 18's SwiftUI release is heavier on developer-experience wins than iOS 26's — two macros that quietly remove real boilerplate, plus a handful of view-level additions (a rebuilt TabView, zoom transitions, scroll-phase observation, mesh gradients) that fill gaps teams had been working around with custom code for years.

#@Entry: environment, focused, and container values without the boilerplate

Before this macro, adding a custom EnvironmentValues key meant defining a private EnvironmentKey struct, a default value, and a computed property extension — three pieces of ceremony for one value. @Entry collapses all of it into one line.

extension EnvironmentValues {
    @Entry var hapticsEnabled: Bool = true
}

The same macro works for FocusedValues and Transferable/ContainerValues entries. Use it every time you'd otherwise hand-write an EnvironmentKey — there's no reason left to write the old three-part version.

#@Previewable: inline state in #Preview

Previews that needed local @State used to require wrapping the previewed view in a throwaway container view just to hold the state. @Previewable lets you declare that state directly inside the #Preview closure.

#Preview {
    @Previewable @State var isOn = false
    Toggle("Enabled", isOn: $isOn)
}

Use this for any preview that needs to exercise interactive state — toggles, text fields, sheet presentation — without littering your view files with preview-only wrapper structs.

#Zoom navigation transitions

.navigationTransition(.zoom) animates a destination view growing out of the exact frame of the element that triggered navigation, paired with .matchedTransitionSource on the source.

@Namespace private var namespace

NavigationLink {
    PhotoDetail(photo: photo)
        .navigationTransition(.zoom(sourceID: photo.id, in: namespace))
} label: {
    Thumbnail(photo: photo)
}
.matchedTransitionSource(id: photo.id, in: namespace)

This is the right default for any grid-to-detail navigation — photo grids, card lists, product catalogs — anywhere the old push transition felt disconnected from what the user tapped.

#Tab and TabSection: a rebuilt TabView

TabView moves from plain view-builder content to explicit Tab values, and gains .sidebarAdaptable, which turns the same tab set into a sidebar on iPad without a second layout to maintain.

TabView {
    Tab("Home", systemImage: "house") {
        HomeView()
    }
    Tab("Search", systemImage: "magnifyingglass") {
        SearchView()
    }
}
.tabViewStyle(.sidebarAdaptable)

If you're currently maintaining a NavigationSplitView on iPad and a TabView on iPhone as two separate code paths, this is worth migrating to directly.

#Scroll phase and geometry observation

.onScrollPhaseChange and .onScrollGeometryChange let you react to scroll state without owning a ScrollViewReader-driven offset tracker.

ScrollView {
    content
}
.onScrollPhaseChange { oldPhase, newPhase in
    if newPhase == .decelerating {
        prefetchNextPage()
    }
}

Reach for this instead of hand-rolled GeometryReader offset math any time you need "user is actively scrolling" or "user reached this threshold" — pagination triggers, sticky header state, and scroll-linked chrome all get simpler.

#MeshGradient

MeshGradient renders a gradient across a grid of control points with individual colors, rather than the two- or three-stop gradients LinearGradient and friends support.

MeshGradient(
    width: 3,
    height: 3,
    points: [
        [0, 0], [0.5, 0], [1, 0],
        [0, 0.5], [0.5, 0.5], [1, 0.5],
        [0, 1], [0.5, 1], [1, 1]
    ],
    colors: [
        .red, .purple, .indigo,
        .orange, .white, .blue,
        .yellow, .green, .mint
    ]
)

This replaces the custom Canvas- or shader-based gradient hacks teams built for marketing screens and onboarding backgrounds.

#What to adopt first

  1. Adopt @Entry everywhere you have a hand-written EnvironmentKey. It's a pure refactor, works at any deployment target your toolchain supports, and has zero runtime cost difference from the code it replaces.
  2. Adopt @Previewable immediately — it only affects preview canvases, not your shipped deployment target, so there's no reason to wait.
  3. Migrate iPad-specific split-view code to TabView with .sidebarAdaptable if you're maintaining two navigation shells today.
  4. Add zoom transitions to your highest-traffic grid-to-detail flow first — it's a visible, cheap win.

Deployment-target reality: @Entry and @Previewable are compile-time macros whose generated code doesn't require iOS 18 at runtime, so they're safe to use even if your deployment target is lower — check that the underlying EnvironmentValues/preview infrastructure you're touching doesn't itself require a newer OS. Zoom transitions, the new Tab API, scroll-phase observation, and MeshGradient are genuine iOS 18 runtime APIs; they need your deployment target at 18 or an if #available(iOS 18, *) fallback path.