SwiftUI.cc
Snippets
DrawingOther ViewsAdvanced

SwiftUI Canvas Drawing Context

Use Canvas when a visual is easier to draw than compose from many nested views, such as sparklines, badges, waveforms, and lightweight charts.

5 min readUpdated 2026-06
Sparkline canvas
import SwiftUI

struct SparklineCanvas: View {
    let values: [Double]

    var body: some View {
        Canvas { context, size in
            guard values.count > 1 else { return }

            let maxValue = values.max() ?? 1
            let points = values.enumerated().map { index, value in
                CGPoint(
                    x: size.width * CGFloat(index) / CGFloat(values.count - 1),
                    y: size.height - size.height * CGFloat(value / maxValue)
                )
            }

            var path = Path()
            path.move(to: points[0])
            points.dropFirst().forEach { path.addLine(to: $0) }

            context.stroke(path, with: .color(.teal), lineWidth: 3)
        }
        .frame(height: 96)
    }
}
Use this when

You need many small drawing operations inside one stable SwiftUI view.

The design is closer to a chart, meter, waveform, or decorative treatment than a hierarchy of controls.

You want drawing code to react to the available size without creating dozens of child views.

Avoid this when

The elements need individual accessibility labels or gestures.

A normal Shape, Image, or stack layout already describes the UI clearly.

The drawing must be edited by designers as asset files.

Implementation notes

Canvas receives a size at render time, so keep calculations relative to that size instead of hard-coding pixel positions.
Immediate-mode drawing is fast for repeated marks, but it does not create separate SwiftUI views for every point.
If parts of the drawing need taps or VoiceOver labels, layer accessible SwiftUI controls above the Canvas.

Checklist

Clamp or normalize incoming values before drawing.

Test light mode, dark mode, and high contrast colors.

Keep expensive data preparation outside the renderer closure when possible.

Related reference