Rotating Words Text
Words that take turns in the same spot, each one pushing the last out of the way.

- Text
- iOS 18.0+
- beginner
- Origin
- Original work
- Found by
- rotating words · word swap · push transition · headline · hero text · cycling text · palabras rotatorias · cambiar palabras · transición · titular · texto cíclico · encabezado
Description
Section titled “Description”Words that take turns in the same spot, each one pushing the last out of the way.
It reserves the width of the longest word, so nothing around it moves. With Reduce Motion on, the words crossfade.
struct RotatingWordsTextDemo: View { var body: some View { ZStack { LinearGradient(colors: [Color(white: 0.12), .black], startPoint: .top, endPoint: .bottom) .ignoresSafeArea()
VStack(alignment: .leading, spacing: 4) { Text("Made for") .foregroundStyle(.white)
RotatingWordsText(words: ["designers", "developers", "dreamers", "everyone"], interval: 1.2) .foregroundStyle(.linearGradient(colors: [.orange, .pink], startPoint: .leading, endPoint: .trailing)) } .font(.system(.largeTitle, design: .rounded, weight: .heavy)) .padding(32) } }}API reference
Section titled “API reference”| Parameter | Type | Default | Description |
|---|---|---|---|
words | [String] | Required | |
interval | Double | 1.6 | Seconds each word stays on screen. |
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
/// Words that take turns in the same spot, each one pushing the last out of the way.////// It reserves the width of the longest word, so nothing around it moves./// With Reduce Motion on, the words crossfade.struct RotatingWordsText: View { let words: [String] /// Seconds each word stays on screen. var interval: Double = 1.6
@State private var index = 0 @Environment(\.accessibilityReduceMotion) private var reduceMotion
private var transition: AnyTransition { reduceMotion ? .opacity : .push(from: .bottom) }
var body: some View { ZStack(alignment: .leading) { ForEach(words.indices, id: \.self) { position in Text(words[position]).hidden() }
if !words.isEmpty { Text(words[index % words.count]) .id(index) .transition(transition) } } .clipped() .accessibilityElement(children: .ignore) .accessibilityLabel(words.joined(separator: ", ")) .task(id: words) { await rotate() } }
private func rotate() async { guard words.count > 1 else { return }
while !Task.isCancelled { try? await Task.sleep(for: .seconds(interval)) guard !Task.isCancelled else { return }
withAnimation(.snappy(duration: 0.45)) { index = (index + 1) % words.count } } }}
// MARK: - Demo
struct RotatingWordsTextDemo: View { var body: some View { ZStack { LinearGradient(colors: [Color(white: 0.12), .black], startPoint: .top, endPoint: .bottom) .ignoresSafeArea()
VStack(alignment: .leading, spacing: 4) { Text("Made for") .foregroundStyle(.white)
RotatingWordsText(words: ["designers", "developers", "dreamers", "everyone"], interval: 1.2) .foregroundStyle(.linearGradient(colors: [.orange, .pink], startPoint: .leading, endPoint: .trailing)) } .font(.system(.largeTitle, design: .rounded, weight: .heavy)) .padding(32) } }}
#Preview { RotatingWordsTextDemo()}