This component no longer exists. It was in atlas-ui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-13 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
Letter Swap
atlas-ui/letter-swapRemovedComponent
A text animation that swaps the letters vertically on hover.
Live preview
live · rendered by the registry
Rendered by atlas-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://atlasui.dev/r/letter-swap.jsonSource
1"use client";23import { useState } from "react";45import { motion, stagger, useAnimate } from "motion/react";67import { cn } from "@/lib/utils";89interface LetterSwapProps {10 text: string;11 reverse?: boolean;12 staggerDuration?: number;13 staggerFrom?: "first" | "last" | "center";14 className?: string;15}1617export const LetterSwap = ({18 text,19 reverse = false,20 staggerDuration = 0.02,21 staggerFrom = "first",22 className,23}: LetterSwapProps) => {24 const [scope, animate] = useAnimate();25 const [isHovered, setIsHovered] = useState(false);2627 const hoverStart = () => {28 if (isHovered) return;29 setIsHovered(true);3031 animate(32 ".letter-primary",33 { y: reverse ? "100%" : "-100%" },34 {35 delay: stagger(staggerDuration, {36 from: staggerFrom,37 }),38 }39 );4041 animate(42 ".letter-secondary",43 { top: "0%" },44 {45 delay: stagger(staggerDuration, {46 from: staggerFrom,47 }),48 }49 );50 };5152 const hoverEnd = () => {53 if (!isHovered) return;54 setIsHovered(false);5556 animate(57 ".letter-primary",58 { y: 0 },59 {60 delay: stagger(staggerDuration, {61 from: staggerFrom,62 }),63 }64 );6566 animate(67 ".letter-secondary",68 { top: reverse ? "-100%" : "100%" },69 {70 delay: stagger(staggerDuration, {71 from: staggerFrom,72 }),73 }74 );75 };7677 return (78 <motion.span79 ref={scope}80 className={cn(81 "relative flex items-center justify-center overflow-hidden",82 className83 )}84 onHoverStart={hoverStart}85 onHoverEnd={hoverEnd}86 >87 <span className="sr-only">{text}</span>8889 {text.split("").map((letter, i) => {90 return (91 <span92 className="relative flex whitespace-pre"93 key={i}94 aria-hidden={true}95 >96 <motion.span className="letter-primary relative" style={{ top: 0 }}>97 {letter}98 </motion.span>99100 <motion.span101 className="letter-secondary absolute"102 style={{ top: reverse ? "-100%" : "100%" }}103 >104 {letter}105 </motion.span>106 </span>107 );108 })}109 </motion.span>110 );111};
What it pulls in
npm packages
Other registry items
