Link
Un enlace en línea, subrayado además de azul, que dice a dónde lleva y parte las URL largas.
Orders over Q500 ship free. See the shipping rates for everything else.
Read the ssntl/ui documentation (opens in a new tab) before you install.
Tracking: https://ssntl.app/orders/2026-10-28/GT-48210/tracking?ref=confirmation-email
Instalación
$ pnpm dlx shadcn@latest add @ssntl/linkUso
import { Link } from "@/components/ui/link"
<p>Consulta las <Link href="/envios">tarifas de envío</Link> para lo demás.</p>
<Link href="https://ui.ssntl.app/docs" external>documentación de ssntl/ui</Link>
<Link asChild><NextLink href="/precios">Precios</NextLink></Link>- Evidente: azul, peso medio y subrayado, así un enlace nunca depende solo del color.
- Descriptivo: el texto nombra el destino (“tarifas de envío”), nunca “haz clic aquí” ni “leer más”.
- Las URL largas se parten donde hace falta en lugar de ensanchar el diseño.
- external abre una pestaña nueva, agrega la flecha, rel="noopener noreferrer" y “(se abre en una pestaña nueva)” para lectores de pantalla (newTabLabel).
Código
import * as React from "react"
import { ArrowUpRight } from "lucide-react"
import { Slot } from "radix-ui"
import { cn } from "@/lib/utils"
// Essential Design links: blue-600 (blue-300 in dark), medium weight and
// always underlined, so a link never depends on color alone. The underline
// starts soft and fills in on hover. Long URLs break instead of overflowing.
function Link({
asChild = false,
external = false,
newTabLabel = "(opens in a new tab)",
className,
children,
...props
}: React.ComponentProps<"a"> & {
/** Render the child element (a framework Link, for example) with these styles. */
asChild?: boolean
/** Opens in a new tab: adds the arrow, rel and a label for screen readers. */
external?: boolean
/** Read after the text of an external link. */
newTabLabel?: string
}) {
const Comp = asChild ? Slot.Root : "a"
return (
<Comp
data-slot="link"
{...(external && { target: "_blank", rel: "noopener noreferrer" })}
className={cn(
"rounded-xs font-medium wrap-break-word text-blue-600 underline decoration-blue-600/40 underline-offset-4 dark:text-blue-300 dark:decoration-blue-300/40",
"transition-[text-decoration-color] duration-(--duration-fast) ease-out hover:decoration-current",
"focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring",
className
)}
{...props}
>
<Slot.Slottable>{children}</Slot.Slottable>
{external && (
<>
<ArrowUpRight
aria-hidden
strokeWidth={1.6}
className="ms-0.5 inline size-4 align-text-bottom"
/>
<span className="sr-only"> {newTabLabel}</span>
</>
)}
</Comp>
)
}
export { Link }