UIPackage
Menu

Link

link ui
Edit on GitHub

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

$ npx shadcn@latest add https://uipkge.dev/r/react/link.json
Named registry: 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

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