Components
Link Preview
Lazily displays a linked page in a hover and keyboard-focus preview.
Preview
Hover or focus the Button documentation to load a live preview without leaving this page.
link-preview.demo.svelte
<script lang="ts"> import { LinkPreview } from '$lib/components/ui/link-preview';</script><p class="max-w-md text-center leading-7 text-muted-foreground"> Hover or focus <LinkPreview href="/docs/components/button" class="text-foreground"> the Button documentation </LinkPreview> to load a live preview without leaving this page.</p>Installation
Install directly from the hosted registry with the shadcn-svelte CLI.
Terminal
npx shadcn-svelte@latest add https://ui.akcodeworks.com/r/link-preview.jsonTerminal
pnpm dlx shadcn-svelte@latest add https://ui.akcodeworks.com/r/link-preview.jsonTerminal
yarn dlx shadcn-svelte@latest add https://ui.akcodeworks.com/r/link-preview.jsonTerminal
bun x shadcn-svelte@latest add https://ui.akcodeworks.com/r/link-preview.jsonUsage
Pass a URL and optional link content. The iframe is created only after hover or keyboard focus opens the preview. Sites may prevent embedding through their security headers.
API reference
| Prop | Type | Default |
|---|---|---|
| href | string | required |
| title | string | Preview of {href} |
| openDelay | number | 300 |
| closeDelay | number | 150 |
| disabled | boolean | false |
| class | string | — |
| contentClass | string | — |
| iframeClass | string | — |
Source
These files are included in the registry item and copied into the consuming project.
link-preview.svelte
<script lang="ts"> import type { Snippet } from 'svelte'; import { LinkPreview as LinkPreviewPrimitive } from 'bits-ui'; import { cw } from '$lib/utils'; let { href, children, title, target, rel, openDelay = 300, closeDelay = 150, disabled = false, class: className, contentClass, iframeClass }: { href: string; children?: Snippet; title?: string; target?: '_self' | '_blank' | '_parent' | '_top'; rel?: string; openDelay?: number; closeDelay?: number; disabled?: boolean; class?: string; contentClass?: string; iframeClass?: string; } = $props(); let open = $state(false); let loading = $state(true); const frameTitle = $derived(title ?? `Preview of ${href}`); function handleOpenChange(nextOpen: boolean) { open = nextOpen; if (nextOpen) loading = true; }</script><LinkPreviewPrimitive.Root {open} onOpenChange={handleOpenChange} {openDelay} {closeDelay} {disabled}> <LinkPreviewPrimitive.Trigger> {#snippet child({ props })} <!-- eslint-disable svelte/no-navigation-without-resolve --> <a {...props} {href} {target} {rel} role={undefined} class={cw( 'font-medium text-foreground underline decoration-border underline-offset-4 transition-colors hover:decoration-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:outline-none', className )} > {#if children} {@render children()} {:else} {href} {/if} </a> <!-- eslint-enable svelte/no-navigation-without-resolve --> {/snippet} </LinkPreviewPrimitive.Trigger> <LinkPreviewPrimitive.Portal> <LinkPreviewPrimitive.Content sideOffset={8} collisionPadding={16} class={cw( 'bg-popover text-popover-foreground z-50 w-[min(24rem,calc(100vw-2rem))] overflow-hidden rounded-xl border border-border shadow-xl outline-none', contentClass )} > <div class="relative h-56 bg-muted"> {#if open} <iframe src={href} title={frameTitle} loading="lazy" sandbox="" onload={() => (loading = false)} class={cw('h-full w-full border-0 bg-background', iframeClass)} ></iframe> {/if} {#if loading} <div class="absolute inset-0 grid place-items-center bg-muted text-sm text-muted-foreground" > Loading preview… </div> {/if} </div> <div class="truncate border-t border-border px-3 py-2 font-mono text-xs text-muted-foreground" > {href} </div> </LinkPreviewPrimitive.Content> </LinkPreviewPrimitive.Portal></LinkPreviewPrimitive.Root>index.ts
export { default as LinkPreview } from './link-preview.svelte';