This article walks through implementing a typewriter-style text animation in SwiftUI using pure Swift and native SwiftUI APIs, no external dependencies.
Minimum supported platforms: iOS 15.0+.
You can jump directly to the code. A complete example repository is provided at the end.

About
This article walks through implementing a typewriter-style effect animation in SwiftUI using pure Swift and native SwiftUI APIs — no external dependencies.
Minimum supported iOS version is 15 and till the latest one iOS 26.
Many existing implementations rely on UIKit wrappers or just string modifications that affect text appearance and doesn’t provide desired animation that fit’s and doesn’t break layout around.
This implementation supports:
- Custom fonts
- Any font size
- Any font color
- Stable layout — the final text size is known in advance, so surrounding views remain unaffected
The key point of the animation effect is to keep a text on same positions aligned to any side and avoid text jumps during animation progress.
Implementation description
Main component of the view is an a AttributedString that used with SwiftUI native Text component that allow full text customizations modifier.
Animations starts with onAppear event on TypwriterText view. It starts with empty view without the text but the view already fill all space required for final text. The view iterates text by charactes and change .clear text color to initial text color provided for the text component. Until the full text is presented. The component provides letters appearance interval modification.
Code
How to use TypewriterText component
TypewriterText("Hello, world! Let's type it out!")
.font(.system(.title2))
.foregroundStyle(Color.brown)
TypewriterText("Hello, world! Let's type it out!")
.font(.custom("Custom-Font", size: 24))
.foregroundStyle(Color.brown)
You can provide any custom or system font and any color that will be animated during typweriter animation.
The TypewriterText looks like this
struct TypewriterText: View {
let text: String
let interval: TimeInterval
@State private var attributedText: AttributedString = ""
init(_ text: String, interval: TimeInterval = 0.06) {
self.text = text
self.interval = interval
}
var body: some View {
Text(attributedText)
.onAppear {
startAnimation()
}
}
@MainActor
private func startAnimation() {
Task { @MainActor in
var base = AttributedString(text)
let initialColor = base.foregroundColor
base.foregroundColor = .clear
attributedText = base
var index = base.startIndex
while index < base.endIndex {
let nextIndex = base.index(afterCharacter: index)
attributedText[index..<nextIndex].foregroundColor = initialColor
index = nextIndex
try? await Task.sleep(nanoseconds: UInt64(interval * 1_000_000_000))
}
}
}
}
It uses AttributedText as main component for dynamic text appearence by changing it’s letters colors one by one.
The usage of native comonents provides good level of performance and open to customizations and modifications.
For example, you can add haptics on each letter appear by modifying startAnimation() adding haptic trigger in while cycle.
You can check example Xcode project by the link.

Top comments (0)