Link
linkuiStyled anchor with external-link handling (target/rel auto-applied for http(s) hrefs). Supports underline variants (always/hover/none), color variants (default/primary/muted), disabled state, left/right icon snippets, size variants, and child-snippet composition.
Installation
$pnpm dlx shadcn-svelte@latest add https://uipkge.dev/r/svelte/link.json$npx shadcn-svelte@latest add https://uipkge.dev/r/svelte/link.json$yarn dlx shadcn-svelte@latest add https://uipkge.dev/r/svelte/link.json$bunx shadcn-svelte@latest add https://uipkge.dev/r/svelte/link.jsonManifest:
https://uipkge.dev/r/svelte/link.jsonInstalls to:src/lib/components/ui/link/Examples
Loading interactive previews…
Loading interactive previews…
Props
| Name | Type / Values | Default | Required |
|---|---|---|---|
underline | 'none''always''hover' | hover | optional |
color | 'default''primary''muted' | primary | optional |
size | 'sm''default''lg' | default | optional |
disabled | boolean | false | optional |
toRouter destination (React `to` parity). Alias for `href` — wins when both are set. | string | — | optional |
externalOpen external href in a new tab. Defaults to true for http(s) hrefs. | boolean | — | optional |
left | Snippet | — | optional |
right | Snippet | — | optional |
children | Snippet | — | optional |
childemitting an <a> — the Svelte counterpart of React's `asChild` (and the idiomatic cover for React's polymorphic `as`). | Snippet<[{ props: Record<string, unknown> }]> | — | optional |
refThe rendered <a>, via `bind:ref`. Stays null in `child` mode. | HTMLAnchorElement | null | — | optional |
npm dependencies
Files installed (3)
src/lib/components/ui/link/Link.svelte2.6 kB
<script lang="ts" module> import type { Snippet } from 'svelte' import type { HTMLAnchorAttributes } from 'svelte/elements' import type { LinkVariants } from './link.variants' export interface LinkProps extends HTMLAnchorAttributes { underline?: LinkVariants['underline'] color?: LinkVariants['color'] size?: LinkVariants['size'] disabled?: boolean /** Router destination (React `to` parity). Alias for `href` — wins when both are set. */ to?: string /** Open external href in a new tab. Defaults to true for http(s) hrefs. */ external?: boolean left?: Snippet right?: Snippet children?: Snippet /** Render your own element with the link's props and styles instead of * emitting an <a> — the Svelte counterpart of React's `asChild` (and the * idiomatic cover for React's polymorphic `as`). */ child?: Snippet<[{ props: Record<string, unknown> }]> /** The rendered <a>, via `bind:ref`. Stays null in `child` mode. */ ref?: HTMLAnchorElement | null } </script> <script lang="ts"> import { cn } from '$lib/utils' import { linkVariants } from './link.variants' let { class: className, underline = 'hover', color = 'primary', size = 'default', disabled = false, to, external, href, child, children, left, right, ref = $bindable(null), onclick, ...restProps }: LinkProps = $props() const resolvedHref = $derived(to ?? href) const isExternal = $derived(external ?? (typeof resolvedHref === 'string' && /^https?:\/\//.test(resolvedHref))) type AnchorClick = Parameters<Exclude<LinkProps['onclick'], null | undefined>>[0] function handleClick(e: AnchorClick) { if (disabled) { e.preventDefault() e.stopPropagation() return } onclick?.(e) } const mergedProps = $derived({ 'data-uipkge': '', 'data-slot': 'link', 'data-underline': underline, 'data-color': color, 'data-size': size, 'data-disabled': disabled ? '' : undefined, href: disabled ? undefined : resolvedHref, 'aria-disabled': disabled ? ('true' as const) : undefined, tabindex: disabled ? -1 : undefined, ...(isExternal && !disabled ? { target: '_blank', rel: 'noopener noreferrer' } : {}), class: cn(linkVariants({ underline, color, size }), disabled && 'pointer-events-none opacity-50', className), onclick: handleClick, ...restProps, }) </script> {#if child} {@render child({ props: mergedProps })} {:else} <a bind:this={ref} {...mergedProps}> {@render left?.()} {@render children?.()} {@render right?.()} </a> {/if}src/lib/components/ui/link/link.variants.ts1 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>src/lib/components/ui/link/index.ts0.1 kB
export { default as Link, type LinkProps } from './Link.svelte' export { linkVariants, type LinkVariants } from './link.variants'
Raw manifest:https://uipkge.dev/r/svelte/link.json