Link
link ui Styled anchor with router integration. Renders an <a> for href, a router-link for to, and handles external links with target/rel. Supports underline variants (always/hover/none), color variants (default/primary/muted), disabled state, left/right icon slots, size variants, and asChild composition.
Also available for Vue ->Installation
$ pnpm dlx shadcn@latest add https://uipkge.dev/r/react/link.json $ npx shadcn@latest add https://uipkge.dev/r/react/link.json $ yarn dlx shadcn@latest add https://uipkge.dev/r/react/link.json $ bunx shadcn@latest add https://uipkge.dev/r/react/link.json npx shadcn@latest add @uipkge-react/link Installs to: components/ui/link/ Examples
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
underline | 'none''always''hover' | hover | optional |
color | 'default''primary''muted' | primary | optional |
size | 'sm''default''lg' | default | optional |
href External URL — renders an <a> with target/rel handling. | string | — | optional |
to Use asChild to render a Next.js <Link> or router-aware anchor instead. | string | object | — | optional |
as | React.ElementType | — | optional |
asChild emitting an <a> — the React equivalent of reka-ui's as-child. Use it to give a Next.js <Link> full link styling. | boolean | — | optional |
external Open external href in a new tab. Defaults to true for http(s) hrefs. | boolean | — | optional |
left Leading icon — the React equivalent of the Vue #left slot. | React.ReactNode | — | optional |
right Trailing icon — the React equivalent of the Vue #right slot. | React.ReactNode | — | optional |
npm dependencies
Files installed (3)
-
components/ui/link/Link.tsx 2.5 kB
import * as React from 'react' import { Slot } from '@radix-ui/react-slot' import { cn } from '@/lib/utils' import { linkVariants, type LinkVariants } from './link.variants' export interface LinkProps extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'color'>, LinkVariants { /** External URL — renders an <a> with target/rel handling. */ href?: string /** Router destination — renders an <a> since there is no vue-router in React. * Use asChild to render a Next.js <Link> or router-aware anchor instead. */ to?: string | object as?: React.ElementType /** Render the child element as the link (merging props/styles) instead of * emitting an <a> — the React equivalent of reka-ui's as-child. Use it to * give a Next.js <Link> full link styling. */ asChild?: boolean /** Open external href in a new tab. Defaults to true for http(s) hrefs. */ external?: boolean /** Leading icon — the React equivalent of the Vue #left slot. */ left?: React.ReactNode /** Trailing icon — the React equivalent of the Vue #right slot. */ right?: React.ReactNode } const Link = React.forwardRef<HTMLAnchorElement, LinkProps>( ( { className, href, to, as: asProp = 'a', asChild = false, underline, color, size, disabled, external, left, right, children, ...props }, ref, ) => { const isExternal = external !== undefined ? external : typeof href === 'string' && /^https?:\/\//.test(href) const resolvedHref = (to as string | undefined) ?? href const externalAttrs = isExternal ? { target: '_blank', rel: 'noopener noreferrer' } : {} const Comp = (asChild ? Slot : asProp) as React.ElementType return ( <Comp data-uipkge="" data-slot="link" data-underline={underline} data-color={color} data-size={size} data-disabled={disabled ? '' : undefined} href={resolvedHref} aria-disabled={disabled ? 'true' : undefined} tabIndex={disabled ? -1 : undefined} className={cn(linkVariants({ underline, color, size }), disabled && 'pointer-events-none opacity-50', className)} ref={ref} {...externalAttrs} {...props} > {asChild ? ( children ) : ( <> {left} {children} {right} </> )} </Comp> ) }, ) Link.displayName = 'Link' export { Link } -
components/ui/link/link.variants.ts 1 kB
import type { VariantProps } from 'class-variance-authority' import { cva } from 'class-variance-authority' export const linkVariants = cva( "inline-flex items-center gap-1.5 font-medium transition-colors duration-200 outline-none focus-visible:ring-ring/50 focus-visible:ring-[3px] rounded-sm [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", { variants: { underline: { none: 'no-underline', always: 'underline underline-offset-4', hover: 'no-underline hover:underline hover:underline-offset-4', }, color: { default: 'text-foreground hover:text-foreground/80', primary: 'text-primary hover:text-primary/80', muted: 'text-muted-foreground hover:text-foreground', }, size: { sm: 'text-xs gap-1', default: 'text-sm', lg: 'text-base', }, }, defaultVariants: { underline: 'hover', color: 'primary', size: 'default', }, }, ) export type LinkVariants = VariantProps<typeof linkVariants> -
components/ui/link/index.ts 0.1 kB
export { Link, type LinkProps } from './Link' export { linkVariants, type LinkVariants } from './link.variants'
Raw manifest: https://uipkge.dev/r/react/link.json