Animated Gradient Text
Text filled with a gradient that drifts endlessly through its letters.

- Text
- iOS 18.0+
- beginner
- Origin
- Original work
- Found by
- gradient text · animated gradient · rainbow · colors · text animation · foreground style · texto degradado · degradado animado · arcoíris · colores · animación de texto · gradiente
Description
Section titled “Description”Text filled with a gradient that drifts endlessly through the letters.
With Reduce Motion on, the gradient stays still.
struct AnimatedGradientTextDemo: View { var body: some View { ZStack { Color.black.ignoresSafeArea()
VStack(spacing: 16) { AnimatedGradientText(text: "Colors that\nnever stand\nstill") .font(.system(.largeTitle, design: .rounded, weight: .black)) .multilineTextAlignment(.center) .scaleEffect(1.3)
AnimatedGradientText(text: "Drifting through every letter", colors: [.mint, .cyan, .indigo], duration: 3) .font(.headline) .padding(.top, 48) } .padding(24) } }}API reference
Section titled “API reference”| Parameter | Type | Default | Description |
|---|---|---|---|
text | String | Required | |
colors | [Color] | [.pink, .orange, .yellow, .mint, .cyan, .purple] | |
duration | Double | 4 | Seconds for the colors to drift one full cycle. |
Copy this code into your project, or download the file.
// SPDX-License-Identifier: MIT// Copyright (c) 2026 Oscar Canton and SwiftUI Blocks contributors
import SwiftUI
/// Text filled with a gradient that drifts endlessly through the letters.////// With Reduce Motion on, the gradient stays still.struct AnimatedGradientText: View { let text: String var colors: [Color] = [.pink, .orange, .yellow, .mint, .cyan, .purple] /// Seconds for the colors to drift one full cycle. var duration: Double = 4
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View { TimelineView(.animation(minimumInterval: 1.0 / 60.0, paused: reduceMotion)) { context in Text(text) .foregroundStyle(gradient(at: reduceMotion ? 0 : context.date.timeIntervalSinceReferenceDate)) } }
/// The gradient holds two copies of the colors and spans two text widths. Sliding it /// left by one width lands on an identical picture, so the loop has no visible seam. private func gradient(at time: TimeInterval) -> LinearGradient { let shift = time.truncatingRemainder(dividingBy: duration) / duration
return LinearGradient( colors: colors + colors + colors.prefix(1), startPoint: UnitPoint(x: -shift, y: 0.5), endPoint: UnitPoint(x: 2 - shift, y: 0.5) ) }}
// MARK: - Demo
struct AnimatedGradientTextDemo: View { var body: some View { ZStack { Color.black.ignoresSafeArea()
VStack(spacing: 16) { AnimatedGradientText(text: "Colors that\nnever stand\nstill") .font(.system(.largeTitle, design: .rounded, weight: .black)) .multilineTextAlignment(.center) .scaleEffect(1.3)
AnimatedGradientText(text: "Drifting through every letter", colors: [.mint, .cyan, .indigo], duration: 3) .font(.headline) .padding(.top, 48) } .padding(24) } }}
#Preview { AnimatedGradientTextDemo()}