Gradient Progress Bar
A rounded progress bar with a gradient fill that glows more strongly as it advances.

- Progress
- iOS 18.0+
- beginner
- Origin
- Original work
- Found by
- progress · bar · gradient · glow · download · linear progress · progreso · barra · degradado · brillo · descarga · resplandor
Description
Section titled “Description”A rounded bar whose gradient fill glows more strongly as it advances.
With Reduce Motion on, the fill changes without animating.
struct GradientProgressBarDemo: View { @State private var progress = 0.08
var body: some View { ZStack { LinearGradient(colors: [.black, .indigo.opacity(0.6)], startPoint: .top, endPoint: .bottom) .ignoresSafeArea()
VStack(alignment: .leading, spacing: 44) { VStack(alignment: .leading, spacing: 18) { Text("Downloading") .font(.headline) .foregroundStyle(.white.opacity(0.75))
Text(progress, format: .percent.precision(.fractionLength(0))) .font(.system(.largeTitle, design: .rounded, weight: .bold)) .monospacedDigit() .foregroundStyle(.white) .contentTransition(.numericText(value: progress))
GradientProgressBar(progress: progress, height: 22, label: "Download") }
row("Maps", value: progress * 0.7, colors: [.mint, .green]) row("Music", value: progress * 0.45, colors: [.orange, .pink]) } .padding(28) } .environment(\.colorScheme, .dark) .task { let values = [0.08, 0.34, 0.62, 1, 0.08] var index = 0 while !Task.isCancelled { try? await Task.sleep(for: .seconds(0.9)) index = (index + 1) % values.count withAnimation(.smooth(duration: 0.3)) { progress = values[index] } } } }
private func row(_ title: LocalizedStringKey, value: Double, colors: [Color]) -> some View { VStack(alignment: .leading, spacing: 10) { Text(title) .font(.subheadline) .foregroundStyle(.white.opacity(0.75))
GradientProgressBar(progress: value, colors: colors, label: title) } }}API reference
Section titled “API reference”| Parameter | Type | Default |
|---|---|---|
progress | Double | Required |
colors | [Color] | [.cyan, .blue, .purple] |
height | CGFloat | 12 |
label | LocalizedStringKey | "Progress" |
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
/// A rounded bar whose gradient fill glows more strongly as it advances.////// With Reduce Motion on, the fill changes without animating.struct GradientProgressBar: View { var progress: Double var colors: [Color] = [.cyan, .blue, .purple] var height: CGFloat = 12 var label: LocalizedStringKey = "Progress"
@Environment(\.accessibilityReduceMotion) private var reduceMotion
private var value: Double { progress.isNaN ? 0 : min(max(progress, 0), 1) }
var body: some View { GeometryReader { proxy in ZStack(alignment: .leading) { Capsule() .fill(.quaternary)
Capsule() .fill(LinearGradient(colors: colors, startPoint: .leading, endPoint: .trailing)) .frame(width: value > 0 ? max(height, proxy.size.width * value) : 0) .shadow(color: (colors.last ?? .blue).opacity(0.25 + 0.55 * value), radius: 3 + 12 * value) } } .frame(height: height) .animation(reduceMotion ? nil : .smooth(duration: 0.6), value: value) .accessibilityElement() .accessibilityLabel(label) .accessibilityValue(Text(value, format: .percent.precision(.fractionLength(0)))) }}
// MARK: - Demo
struct GradientProgressBarDemo: View { @State private var progress = 0.08
var body: some View { ZStack { LinearGradient(colors: [.black, .indigo.opacity(0.6)], startPoint: .top, endPoint: .bottom) .ignoresSafeArea()
VStack(alignment: .leading, spacing: 44) { VStack(alignment: .leading, spacing: 18) { Text("Downloading") .font(.headline) .foregroundStyle(.white.opacity(0.75))
Text(progress, format: .percent.precision(.fractionLength(0))) .font(.system(.largeTitle, design: .rounded, weight: .bold)) .monospacedDigit() .foregroundStyle(.white) .contentTransition(.numericText(value: progress))
GradientProgressBar(progress: progress, height: 22, label: "Download") }
row("Maps", value: progress * 0.7, colors: [.mint, .green]) row("Music", value: progress * 0.45, colors: [.orange, .pink]) } .padding(28) } .environment(\.colorScheme, .dark) .task { let values = [0.08, 0.34, 0.62, 1, 0.08] var index = 0 while !Task.isCancelled { try? await Task.sleep(for: .seconds(0.9)) index = (index + 1) % values.count withAnimation(.smooth(duration: 0.3)) { progress = values[index] } } } }
private func row(_ title: LocalizedStringKey, value: Double, colors: [Color]) -> some View { VStack(alignment: .leading, spacing: 10) { Text(title) .font(.subheadline) .foregroundStyle(.white.opacity(0.75))
GradientProgressBar(progress: value, colors: colors, label: title) } }}
#Preview { GradientProgressBarDemo()}