Skip to content
Tier

Link

Pro

Sets how Candor's items draw a link to an address in the app, so a press goes through the app's router (no full page load, the router's prefetching and transitions) rather than a plain <a>. Items that link to another site, open a new tab or download a file keep their plain <a>. CandorProvider's link sets it for the whole app.

"use client"
import NextLink from "next/link"
import { LinkProvider, type LinkRender } from "@/lib/candor/link"

const link: LinkRender = (props) => <NextLink {...props} />

export function Providers({ children }: { children: React.ReactNode }) {
  return <LinkProvider link={link}>{children}</LinkProvider>
}

Without one, or with link left out, items draw the plain <a> they always have (or the one a LinkProvider above sets).

Markdown
Version 5.2.0· other versions

This page is for 5.2.0, the current release. An earlier release’s page is the Markdown that release published, so the docs match the version you have installed (candor-lock.json records it).

Not in the docs of 1.3.0, 1.4.0, 1.5.0, 1.5.1, 1.6.0, 1.7.0, 1.8.0, 1.8.1, 1.9.0, 1.9.1, 2.0.0, 2.1.0, 2.2.0, 2.3.0, 2.4.0, 2.5.0, 2.5.1, 2.6.0, 2.6.1, 2.6.2, 2.7.0, 2.8.0, 2.9.0, 2.10.0, 3.0.0, 4.0.0, 4.0.1, 4.0.2, 4.1.0, 4.2.0, 4.3.0, 4.4.0, 4.5.0 and 5.0.0: the page came later, or had another name then.

Docs pages weren’t kept for 1.0.0, 1.0.1, 1.1.0, 1.1.1, 1.2.0 and 1.2.1: they are kept from 1.3.0 on, and before that only llms.txt was published.

Preview

Loading the preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/link

Brings in: tokens

Usage

TSX · The example above
"use client"

import * as React from "react"
import { LinkProvider, type LinkRender } from "@/lib/candor/link"
import { NeedsYouLine } from "@/components/candor/needs-you-line"
import { DetailsList } from "@/components/candor/details-list"

export default function Example() {
  const [went, setWent] = React.useState<string | null>(null)
  // The app's router, as a stand-in. In a Next.js app the render is `(props) => <NextLink {...props} />`, defined once
  // outside a component; here a plain click stays on the page and says where the router would have gone.
  const routerLink = React.useCallback<LinkRender>(
    ({ href, children, onClick, ...props }) => (
      <a
        {...props}
        href={href}
        onClick={(e) => {
          onClick?.(e)
          if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
          e.preventDefault()
          setWent(href)
        }}
      >
        {children}
      </a>
    ),
    []
  )
  return (
    <LinkProvider link={routerLink}>
      <div className="flex max-w-lg flex-col gap-4">
        <NeedsYouLine count={3} href="/approvals" />
        <DetailsList groups={[{ id: "run", title: "Run", rows: [{ label: "Logs", value: "Open the logs", kind: "link", href: "/runs/42/logs" }] }]} />
        <p className="text-sm text-muted-foreground" role="status">
          {went ? `The router went to ${went}, with no page load.` : "Press a link: the app's router follows it."}
        </p>
      </div>
    </LinkProvider>
  )
}

<LinkProvider>

PropTypeDefaultDescription
linkLinkRender | undefined—The app's link render, defined once outside a component so it stays the same. Left out, a LinkProvider above sets it, else a plain `<a>`.
childrenrequiredReact.ReactNode—What goes inside.

Functions

useLink()

The link render to draw an in-app address with: the app's, from the nearest LinkProvider (or CandorProvider's link), else one that draws a plain <a>. Call it with the address and everything the <a> would have had:

const link = useLink()
return link({ href: "/runs/42", className: "underline", children: "Open the run" })

Types

LinkRenderProps
What an item hands the app's link render: the address, what the link holds, and every other attribute the item's `<a>` would have had (its classes, `data-slot`, `aria-*`, handlers and ref). Pass them all on.
Omit<React.ComponentPropsWithRef<"a">, "href" | "className" | "children"> & { /** Where the link goes: an address in the app ("/runs/42"), as the app gave it to the item. */ href: string; /** The item's classes for the link. */ className?: string | undefined; /** What the link holds: its words, an icon. */ children?: React.ReactNode | undefined; /** The item's `data-*` attributes (its `data-slot`, say), which the app's link passes on with the rest. */ [data: `data-${string}`]: string | number | boolean | undefined; }
LinkRender
Draws a link the app's router follows. It is called as a function while an item draws, so it returns an element and calls no hooks itself: `(props) => <NextLink {...props} />` for Next.js, `({ href, ...props }) => <Link to={href} {...props} />` for TanStack Router.
(props: LinkRenderProps) => React.ReactElement