ComponentsRiserva spazio col più lungo (invisible spacer), absolute layer animato sopra. useState index + setInterval.
TextMorphClient
Esempio01
morphing-text.tsx 001Default · 3 phrases002Hero · use cases for the catalogI componenti servono perDocumentazioneLanding
003Faster · 4 quick rotations tsxsrc/components/morphing-text.tsx
"use client";
import { useEffect, useState } from "react";
import { cn } from "@/lib/utils";
export type MorphingTextProps = {
texts: string[];
/** Total cycle per word in ms (steady + transition). Default 2500. */
duration?: number;
className?: string;
};
/**
* <MorphingText/> — two stacked layers cross-fade with a blur+opacity morph
* between strings. Overlays each `text` in turn; the parent reserves space
* via the longest string rendered as an invisible spacer.
*/
export function MorphingText({ texts, duration = 2500, className }: MorphingTextProps) {
const [index, setIndex] = useState(0);
useEffect(() => {
if (texts.length < 2) return;
const id = setInterval(() => {
setIndex((i) => (i + 1) % texts.length);
}, Math.max(900, duration));
return () => clearInterval(id);
}, [texts.length, duration]);
const longest = texts.reduce((a, b) => (b.length > a.length ? b : a), "");
return (
<>
<style>{`
@keyframes morphing-text-in {
0% { opacity: 0; filter: blur(8px); transform: translateY(6px) scale(0.98); }
100% { opacity: 1; filter: blur(0); transform: translateY(0) scale(1); }
}
`}</style>
<span className={cn("relative inline-block align-baseline", className)}>
<span aria-hidden className="invisible inline-block">
{longest}
</span>
<span
key={index}
className="absolute inset-0 inline-flex items-center justify-center"
style={{
animation: "morphing-text-in 700ms var(--ease-in-out) both",
}}
>
{texts[index]}
</span>
</span>
</>
);
}
Note — Lo spacer invisibile garantisce che il box non collassi quando un testo è più corto. Min duration 900ms.
Prompt LLM02
Incolla in Claude o ChatGPT per generare la tua variante. Include il contesto del brand, i token e i vincoli del progetto.
Sei un senior frontend engineer. Stai lavorando su un sito Next.js 16 + React 19 + Tailwind v4 in italiano, look chanhdai-inspired: colonna stretta 672px, Geist Sans + Geist Mono, hairline 1px, divisori a stripe diagonale, palette zinc.
Token CSS disponibili: --bg, --bg-alt, --fg, --fg-muted, --fg-soft, --border, --border-strong, --accent. Usa SEMPRE queste variabili tramite le utility tailwind generate (bg-bg, text-fg-muted, border-border, ecc.). Helper "cn" da "@/lib/utils". Niente librerie UI extra: solo lucide-react e tailwind-merge.
Genera un componente <MorphingText> per cross-fade morph tra stringhe.
Props:
- texts: string[].
- duration?: number (ms per ciclo, default 2500).
- className?: string.
Implementazione:
- "use client". useState<number> index, useEffect setInterval.
- Wrapper relative inline-block. Span invisibile col testo più lungo come spacer.
- Span absolute inset-0 chiave key={index} con keyframe morphing-text-in (opacity 0→1, blur 8px→0, translateY 6px→0, scale 0.98→1) 700ms var(--ease-in-out) both.
Output: file completo src/components/morphing-text.tsx.Uso tipico03
<MorphingText texts={["a", "b", "c"]} duration={2500} />
Dipendenze04
Ti è servito? Dimmelo, oppure proponi il prossimo componente.