Snippets
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
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)
}
}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
SwiftUI Shapes, Path, Trim, and Stroke
Build reusable visual primitives with Shape, Path, stroke, fill, and trim instead of baking every decoration into image assets.
SwiftUI Gradients and ShapeStyle
Choose linear, radial, angular, image, and mesh-style fills based on the job the color is doing in the interface.
SwiftUI drawingGroup and Compositing Effects
Use compositingGroup and drawingGroup to control how SwiftUI combines effects, shadows, opacity, and complex drawing.