TechnologiesSwiftUI

TimelineView struct

iOSmacOStvOSwatchOSvisionOSiOS 15.0+✓ renders

A view that updates according to a schedule that you provide.

How it works

TimelineView is a container view that updates its content according to a schedule you provide, redrawing itself at each point on a timeline rather than only when its observed state changes. Reach for it when a view must reflect the passage of time on its own — a clock, a countdown, a progress ring, or an animation that advances at fixed intervals — without you managing a Timer, publisher, or manual state updates. You describe when to refresh by passing a TimelineSchedule, and SwiftUI invokes your content closure at each scheduled instant, handing it a context that carries the current date.

  1. Drive updates with a TimelineSchedule

    The first initializer argument is a value conforming to TimelineSchedule that defines the sequence of dates at which the view refreshes. Here .periodic(from: .now, by: 1) produces a tick once every second starting at the current moment; other schedules include .everyMinute, .animation, and .explicit(_:) for an exact list of dates.

  2. Receive the timeline context in the content closure

    TimelineView's trailing closure is its ViewBuilder content, called fresh at each scheduled update with a TimelineViewDefaultContext value. The example binds it as context, and its context.date property holds the date for the current invocation — the source of truth for whatever the view should display at that instant.

  3. Build the per-tick content from the context's date

    Whatever views you return from the closure are re-evaluated on every tick, so reading context.date makes the UI track time automatically. The example feeds it into Text(context.date, style: .time), which renders the live clock face that changes each second as the schedule fires.

  4. Compose and style like any other view

    TimelineView is itself a View, so it slots into a body and accepts modifiers and child layout as usual — the surrounding VStack and the trailing .padding() apply to it exactly as they would to any container. The timeline behavior is confined to the schedule and the closure; the rest is ordinary SwiftUI composition.

Try it — Change .periodic(from: .now, by: 1) to .periodic(from: .now, by: 0.1) and watch the Text(context.date, style: .time) clock refresh ten times a second instead of once.

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.

TimelineView.swift
struct TimelineViewDemo: View {
    var body: some View {
        TimelineView(.periodic(from: .now, by: 1)) { context in
            VStack(spacing: 8) {
                Text("Live Clock")
                    .font(.headline)
                Text(context.date, style: .time)
                    .font(.system(.largeTitle, design: .monospaced))
                    .foregroundStyle(.tint)
            }
        }
        .padding()
    }
}
Live preview
Live Clock context.date
Live Clock context.date
swift → lexer → parser → sema → uiir → canvas Open in Studio ↗
What's new in SwiftUI 27 →