Swapping Text

Text that swaps to a new value letter by letter, each changed letter sliding out as the new one slides in.

<script setup lang="ts">
import type { SwappingTextDirection } from '@animate-ui/vue/primitives/texts/swapping'
import { SwappingText } from '@animate-ui/vue/primitives/texts/swapping'

withDefaults(
  defineProps<{
    direction?: SwappingTextDirection
    stagger?: number | string
    duration?: number | string
  }>(),
  { direction: 'up', stagger: 0.07, duration: 2000 },
)

const WORDS = ['Design', 'Develop', 'Deploy']
</script>

<template>
  <span class="inline-grid justify-items-start text-4xl font-semibold">
    <span
      v-for="word in WORDS"
      :key="word"
      aria-hidden="true"
      class="invisible col-start-1 row-start-1"
    >{{ word }}</span>
    <span class="col-start-1 row-start-1 w-0 whitespace-nowrap">
      <SwappingText
        :text="WORDS"
        :direction="direction"
        :stagger="Number(stagger)"
        :duration="Number(duration)"
      />
    </span>
  </span>
</template>

Installation

npm install @animate-ui/vue motion-v
pnpm add @animate-ui/vue motion-v
yarn add @animate-ui/vue motion-v
bun add @animate-ui/vue motion-v

Usage

<script setup lang="ts">
import { SwappingText } from '@animate-ui/vue/primitives/texts/swapping';

defineProps<{ isPublic: boolean }>();
</script>

<template>
  <SwappingText :text="isPublic ? 'Public' : 'Private'" />
</template>

Given an array, it swaps from one text to the next on its own, every duration milliseconds, like Rotating Text:

<SwappingText :text="['Design', 'Develop', 'Deploy']" />

Animation

  • When text changes (or, given an array, every duration milliseconds), the letters are compared position by position. A letter that stays the same doesn't move; every other one swaps in place.
  • The old letter slides up by half a line, fading and blurring out, while the new one slides up from below, unblurring in, in 0.2s. direction="down" reverses both.
  • Changed letters start one after another, from left to right, stagger seconds apart (0.04s).
  • Each letter's width glides from the old letter's to the new one's, so the word grows or shrinks smoothly. Extra letters fade out to nothing.
  • <AnimateUIProvider :tempo> paces the default transition.
  • Given an array, it loops back to the first text after the last, and waits while off screen or while the tab is hidden.
  • Under reduced motion, the text changes at once.
  • Screen readers read the current text once.

API Reference

SwappingText

PropTypeDefault
text
string | string[]-
duration?
number2000
delay?
number0
direction?
'up' | 'down''up'
stagger?
number0.04
transition?
Transition{ duration: 0.2, ease: [0.4, 0, 0.2, 1] }
...props?
HTMLAttributes-

Built by Skyleen. The source code is available on GitHub.

Last updated: 10/23/2026