Sliding Text

Text that slides out of its box while a copy slides in, on hover or on click, like a menu link.

<script setup lang="ts">
import type { SlidingTextDirection, SlidingTextTrigger } from '@animate-ui/vue/primitives/texts/sliding'
import { SlidingText } from '@animate-ui/vue/primitives/texts/sliding'
import { Button } from '@/components/ui/button'

withDefaults(
  defineProps<{ direction?: SlidingTextDirection, trigger?: SlidingTextTrigger }>(),
  { direction: 'down', trigger: 'hover' },
)
</script>

<template>
  <div class="flex flex-col items-center gap-8">
    <SlidingText
      :key="`${direction}-${trigger}`"
      :direction="direction"
      :trigger="trigger"
      class="cursor-pointer text-4xl font-semibold"
      text="Sliding Text"
    />
    <Button as-child size="lg">
      <a href="#" @click.prevent>
        <SlidingText
          :key="`link-${direction}-${trigger}`"
          :direction="direction"
          :trigger="trigger"
          text="Get started"
        />
      </a>
    </Button>
  </div>
</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 { SlidingText } from '@animate-ui/vue/primitives/texts/sliding';
</script>

<template>
  <a href="/docs">
    <SlidingText text="Docs" />
  </a>
</template>

Animation

  • The text sits in a box that clips it. On hover, it slides out by its own height plus a small gap (0.6em) while a copy of it slides in from the other side, in 0.25s on an ease-in-out.
  • direction="down" sends the text down and brings the copy from above; direction="up" does the opposite.
  • With trigger="hover", leaving slides it back the other way. Left halfway, it turns back from where it is.
  • With trigger="click", each click slides it once more in the same direction. A click during a slide carries it on without a jump.
  • The box keeps the text's size and baseline, so it fits inside a line, a link or a button. A text on several lines slides as a whole.
  • Inside a link or a button (or an element with role="button" or role="link"), the whole control slides it: hovering or clicking its padding counts, not just the text.
  • <AnimateUIProvider :tempo> paces the default transition.
  • Under reduced motion, the text doesn't move.
  • Screen readers read the text once: the copy is hidden from them.

API Reference

SlidingText

PropTypeDefault
text
string-
direction?
'down' | 'up''down'
trigger?
'hover' | 'click''hover'
transition?
Transition{ duration: 0.25, ease: [0.4, 0, 0.2, 1] }
...props?
Omit<HTMLMotionProps<'span'>, 'children'>-

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

Last updated: 10/23/2026