Ir al contenido
Evaluar mi proyecto
Componentes · Texto y animacionesDisponible

Texto con subrayado que se dibuja

Énfasis tipográfico con una línea SVG que se dibuja una sola vez; el texto siempre está visible y legible.

Menos ruido. Más intención.

Demostración interactiva

Código completo

Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.

texto-subrayado.tsx51 líneas
Descargar
"use client";

import { type CSSProperties } from "react";

/** Texto con subrayado que se dibuja. React + TypeScript, sin dependencias. Personaliza con variables --gcxu-*. */
export type TextoSubrayadoProps = {
  before?: string;
  emphasis?: string;
  after?: string;
  className?: string;
  style?: CSSProperties;
};

const CSS = `
.gcxu-root { box-sizing: border-box; min-width: 0; max-width: 100%; color: var(--gcxu-fg, #202421); font: 400 15px/1.5 ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
.gcxu-root *, .gcxu-root *::before, .gcxu-root *::after { box-sizing: border-box; }
.gcxu-root button, .gcxu-root input, .gcxu-root textarea, .gcxu-root select { font: inherit; }
.gcxu-root button, .gcxu-root a { -webkit-tap-highlight-color: transparent; }
.gcxu-root :focus-visible { outline: 2px solid var(--gcxu-accent, #25724b); outline-offset: 4px; }
.gcxu-root ::selection { background: var(--gcxu-accent, #25724b); color: #fff; }
.gcxu-root button:disabled { opacity: .5; cursor: not-allowed; }
.gcxu-root svg { flex-shrink: 0; }
@media (prefers-reduced-motion: reduce) { .gcxu-root *, .gcxu-root *::before, .gcxu-root *::after { animation: none !important; transition-duration: .01ms !important; scroll-behavior: auto !important; } }
.gcxu-root { width:600px; margin:0; padding:20px 10px; text-align:center; font-size:clamp(32px,6vw,56px); line-height:1.3; font-weight:600; letter-spacing:-.03em; color:var(--gcxu-fg,#292823); }
.gcxu-root span { position:relative; display:inline-block; }
.gcxu-root svg { position:absolute; width:100%; height:14px; bottom:-4px; left:0; fill:none; stroke:var(--gcxu-accent,#b95131); stroke-width:3; stroke-linecap:round; overflow:visible; }
.gcxu-root path { stroke-dasharray:320; stroke-dashoffset:0; animation:gcxu-draw 1s cubic-bezier(.16,1,.3,1) both; }
@keyframes gcxu-draw { from { stroke-dashoffset:320; } to { stroke-dashoffset:0; } }`;

export function TextoSubrayado({
  before = "Menos ruido.",
  emphasis = "Más intención.",
  after = "",
  className = "",
  style,
}: TextoSubrayadoProps) {
  return (
    <p className={`gcxu-root ${className}`} style={style}>
      <style>{CSS}</style>
      {before}{" "}
      <span>
        {emphasis}
        <svg viewBox="0 0 300 16" preserveAspectRatio="none" aria-hidden="true">
          <path d="M2 11 Q80 0 150 9 T298 5" />
        </svg>
      </span>
      {after && ` ${after}`}
    </p>
  );
}

Úsalo en tu proyecto

Instálalo con la CLI de shadcn.

terminal.sh1 líneas
npx shadcn@latest add https://www.gassierconsulting.com/r/texto-subrayado

Ejemplo de uso de Texto con subrayado que se dibuja

Después de copiar texto-subrayado.tsx a tu proyecto, impórtalo y colócalo donde lo necesites.

ejemplo.tsx5 líneas
import { TextoSubrayado } from "./texto-subrayado";

export default function Ejemplo() {
  return <TextoSubrayado before="Ejemplo" />;
}

Propiedades de TextoSubrayado

TextoSubrayado acepta 5 propiedades: todas son opcionales y tienen un valor por defecto, así que funciona sin configurar nada.

PropiedadTipoDescripción
before?stringOpcional.
emphasis?stringOpcional.
after?stringOpcional.
className?stringOpcional.
style?CSSPropertiesOpcional.

Personaliza Texto con subrayado que se dibuja 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.

VariableValor por defecto
--gcxu-fg#202421
--gcxu-accent#25724b

Accesibilidad y rendimiento

El archivo tiene 51 líneas (2 KB) y define 1 animación con @keyframes. Esto es lo que hace Texto con subrayado que se dibuja por quien lo usa:

  • Detecta prefers-reduced-motion y baja o quita el movimiento cuando la persona lo pide.
  • Muestra un anillo de foco visible al navegar con teclado (:focus-visible).
  • Expone su estado a tecnologías de apoyo con atributos aria-*.
  • Es un componente de cliente de Next.js: incluye la directiva "use client".
Licencia
MIT
Dependencias
React >=18
Compatibilidad
React 18 y 19 · Next.js (componente de cliente)