
Implementing draw animations for SF Symbols in SwiftUI
Learn how to apply the new draw animations of SF Symbols 7 in a SwiftUI app.
When adding visuals to your SwiftUI app, SF Symbols have always been a reliable choice to maintain consistency with Apple's Human Interface Guidelines in iconography. With SF Symbols 7 and iOS 26, Apple introduces draw animations, a new feature that brings icons to life.
Unlike traditional animations that fade, scale, or bounce, draw animations simulate the natural flow of drawing a symbol with a pen, creating more engaging and expressive user interfaces. The result is a more expressive and intentional effect that feels crafted, dynamic, and human.
Example of using Draw On and Draw Off using the symbol "scribble"
SF Symbols are built using multiple layers that define different parts of the symbol. Understanding this structure is crucial because draw animations can target these layers in different ways.

When implementing draw animations, you have three distinct approaches: whole symbol, by layer and individually.
.wholeSymbol
: All layers animate simultaneously, creating a unified drawing effect where the entire symbol appears to be traced at once.
Whole Symbol animation using symbol "signature"
.byLayer
: Layers animate with staggered timing (this is the default behavior). Each layer starts drawing slightly after the previous one, creating depth.
By Layer animation using symbol "signature"
.individually
: Layers animate sequentially, waiting for each layer to complete before starting the next. This creates the most deliberate, step-by-step drawing effect.
Individual Layers Animation using symbol "signature"
Implementing draw animations in SwiftUI
Draw animations in SwiftUI are implemented using the symbolEffect(_:options:isActive:)
modifier.
Effect types
The primary effect types are drawOn
and drawOff
:
// Draw On: animates the symbol appearing
Image(systemName: "checkmark.circle")
.symbolEffect(.drawOn, isActive: isComplete)
// Draw Off: animates the symbol disappearing
Image(systemName: "checkmark.circle")
.symbolEffect(.drawOff, isActive: isHidden)
Animation options
Layer control determines how the symbol's layers are animated:
// Default staggered animation
Image(systemName: "square.and.arrow.up")
.symbolEffect(.drawOn.byLayer, isActive: showSquare)
// All layers at once
Image(systemName: "square.and.arrow.up")
.symbolEffect(.drawOn.wholeSymbol, isActive: showSquare)
// Sequential layer animation
Image(systemName: "square.and.arrow.up")
.symbolEffect(.drawOn.individually, isActive: showSquare)
Modifier options
You can customize the animation behavior with additional options, for example:
// Non-repeating animation (runs once)
.symbolEffect(.drawOn, options: .nonRepeating, isActive: showSquare)
// Faster animation speed
.symbolEffect(.drawOn, options: .speed(2.0), isActive: showSquare)
// Repeating animation
.symbolEffect(.drawOn, options: .repeat(.continuous), isActive: showSquare)
The isActive
parameter
The isActive
parameter controls when the animation should be active and requires state management. In the example below when the value of isDrawing
is true
, the animation runs:
struct ContentView: View {
// Controls animation state
@State private var isDrawing = false
var body: some View {
Image(systemName: "signature")
.symbolEffect(.drawOn, isActive: isDrawing)
Button("Draw") {
// Activates and deactivates the animation
isDrawing.toggle()
}
}
}
And that's it! By combining symbolEffect(_:options:isActive:)
with proper state management, you've unlocked the power of SF Symbols 7's draw animations. Whether you choose byLayer
, individually
, or wholeSymbol
, your users will experience the hand-drawn feel that brings your interface to life!