Palabra que se enfoca
Frase con una palabra que cambia saliendo del desenfoque, como una lente que busca el punto; se pausa fuera de pantalla.
Software paraordenar
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
"use client";
import { useEffect, useRef, useState, type CSSProperties } from "react";
/** Palabra que se enfoca desde el desenfoque y cambia de una frase a otra, como una lente que busca el punto. Se pausa fuera de pantalla. React + TypeScript, sin dependencias. */
export type TextoEnfoqueProps = {
prefix?: string;
words?: string[];
interval?: number;
className?: string;
style?: CSSProperties;
};
const CSS = `
.gctef-root { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: .3em; max-width: 100%; color: var(--gctef-fg, #e9ecf2); font: 600 clamp(28px, 6vw, 60px)/1.2 ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif; letter-spacing: -.03em; }
.gctef-root *, .gctef-root *::before, .gctef-root *::after { box-sizing: border-box; }
.gctef-slot { position: relative; display: inline-grid; }
.gctef-word { grid-area: 1 / 1; color: var(--gctef-hi, #6fb1ff); animation: gctef-in 1s cubic-bezier(.16, 1, .3, 1) both; white-space: nowrap; }
.gctef-sizer { grid-area: 1 / 1; visibility: hidden; height: 0; overflow: hidden; white-space: nowrap; }
@keyframes gctef-in { from { filter: blur(14px); opacity: 0; letter-spacing: .25em; transform: scale(1.06); } to { filter: blur(0); opacity: 1; letter-spacing: inherit; transform: none; } }
@media (prefers-reduced-motion: reduce) { .gctef-word { animation: none; } }`;
export function TextoEnfoque({ prefix = "Software para", words = ["ordenar", "automatizar", "conectar", "escalar"], interval = 2600, className = "", style }: TextoEnfoqueProps) {
const ref = useRef<HTMLSpanElement>(null);
const [i, setI] = useState(0);
const [visible, setVisible] = useState(true);
useEffect(() => {
const el = ref.current;
if (!el) return;
const io = new IntersectionObserver(([entry]) => setVisible(entry.isIntersecting), { threshold: 0.1 });
io.observe(el);
return () => io.disconnect();
}, []);
useEffect(() => {
if (!visible || words.length < 2 || window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
const id = window.setInterval(() => {
if (!document.hidden) setI((value) => (value + 1) % words.length);
}, interval);
return () => window.clearInterval(id);
}, [visible, words.length, interval]);
return (
<span ref={ref} className={`gctef-root ${className}`} style={style}>
<style>{CSS}</style>
<span>{prefix}</span>
<span className="gctef-slot">
{words.map((word) => (
<span key={word} className="gctef-sizer" aria-hidden="true">
{word}
</span>
))}
<span key={i} className="gctef-word" aria-label={words[i]}>
{words[i]}
</span>
</span>
</span>
);
}
Úsalo en tu proyecto
Instálalo con la CLI de shadcn.
npx shadcn@latest add https://www.gassierconsulting.com/r/texto-enfoqueEjemplo de uso de Palabra que se enfoca
Después de copiar texto-enfoque.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.
import { TextoEnfoque } from "./texto-enfoque";
export default function Ejemplo() {
return <TextoEnfoque prefix="Ejemplo" />;
}Propiedades de TextoEnfoque
TextoEnfoque acepta 5 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.
| Propiedad | Tipo | Descripción |
|---|---|---|
prefix? | string | Opcional. |
words? | string[] | Opcional. |
interval? | number | Opcional. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
Personaliza Palabra que se enfoca con variables CSS
Define estas variables en el contenedor o en tu hoja de estilos para cambiar los colores sin tocar el componente. Si no las defines, se usa el valor por defecto.
| Variable | Valor por defecto |
|---|---|
--gctef-fg | #e9ecf2 |
--gctef-hi | #6fb1ff |
Accesibilidad y rendimiento
El archivo tiene 60 líneas (3 KB) y define 1 animación con @keyframes. Esto es lo que hace Palabra que se enfoca por quien lo usa:
- Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
- Expone su estado a tecnologías de apoyo con atributos aria-*.
- Se pausa cuando sale de la pantalla para no gastar batería ni CPU.
- Es un componente de cliente de Next.js: incluye la directiva "use client".