Wave Letters

Letters hop one after another so a soft wave keeps rolling through the word.

  • CSS
  • Text
  • Loop
  • Added

AI prompt

Make a CSS wave text animation in React. Split the text "Hello there" into one inline-block <span> per character with Array.from, and set a --i custom property on each span to its index. Animate every span with the same keyframe: translateY 0 at 0%, -0.3em at 30%, back to 0 at 60% and hold until 100%, over 1.6s with cubic-bezier(0.65, 0, 0.35, 1), infinite. Offset each letter with animation-delay: calc(var(--i) * 70ms). Replace spaces with a non-breaking space so they keep their width. Put the original text in aria-label on the wrapper and aria-hidden on the spans. Turn the animation off under prefers-reduced-motion.

Source

Demo.tsx
'use client'

import s from './demo.module.css'

export default function WaveLetters({ labels }: { labels: Record<string, string> }) {
  return (
    <p className={s.text} aria-label={labels.text}>
      {Array.from(labels.text).map((ch, i) => (
        <span key={i} className={s.ch} style={{ '--i': i } as React.CSSProperties} aria-hidden="true">
          {ch === ' ' ? ' ' : ch}
        </span>
      ))}
    </p>
  )
}
demo.module.css
.text {
  display: flex;
  margin: 0;
  font: 700 2.4rem / 1 var(--font-display);
  letter-spacing: -0.02em;
  color: var(--stage-ink);
  white-space: nowrap;
}

.ch {
  display: inline-block;
  animation: wave 1.6s var(--ease-in-out) infinite;
  animation-delay: calc(var(--i) * 70ms);
}

.ch:nth-child(3n) { color: var(--stage-accent); }

@keyframes wave {
  0%, 60%, 100% { transform: translateY(0); }
  30% { transform: translateY(-0.3em); }
}

@media (prefers-reduced-motion: reduce) {
  .ch { animation: none; }
}

Suggest an idea

Seen a motion or a theme you would like to find here? Describe it, and it opens as a prefilled GitHub issue for you to post.

What are you suggesting?

Needs a GitHub account. Suggestions are public.