# Link

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.

```tsx
"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).

- Registry name: `link` (`@candor/link`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/link

## Install

```bash
npx candor-ui add link
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/link`.
It brings in: tokens.

## Example

```tsx
"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>

Props:

- `link?: LinkRender | 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>`.
- `children: React.ReactNode`

## Functions

### useLink

```ts
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:

```tsx
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.

```ts
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.

```ts
(props: LinkRenderProps) => React.ReactElement
```

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
