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.
Código completo
Es exactamente el archivo que se descarga. Cópialo a tu proyecto y úsalo.
"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.
npx shadcn@latest add https://www.gassierconsulting.com/r/texto-subrayadoEjemplo 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.
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.
| Propiedad | Tipo | Descripción |
|---|---|---|
before? | string | Opcional. |
emphasis? | string | Opcional. |
after? | string | Opcional. |
className? | string | Opcional. |
style? | CSSProperties | Opcional. |
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.
| Variable | Valor 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".