> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Link - Web (AI Kit)

> Links navigate users to another page or location.

> [!NOTE]
>
> For development, import `Link` from
> `@servicetitan/anvil2-ai-kit`. For design, find it in the
> [AI Kit Web Component Library file](https://www.figma.com/design/QEIsArLktLeJAaFvcpw3PO/AI-Kit-Web-Component-Library).

ai-kit-link

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link?file=src/App.tsx)

```tsx lines theme={null}
import { Link } from "@servicetitan/anvil2-ai-kit";

function App() {
  return <Link text="Go to dashboard" href="/dashboard" />;
}

export default App;
```

## Options

The Link supports same-page or new-tab navigation and reads naturally either on its own or inline within body text.

### Target

ai-kit-link-target

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link-target?file=src/App.tsx)

```tsx lines theme={null}
import { Link } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      {/* Same-page navigation (default) */}
      <Link text="Go to dashboard" href="/dashboard" />

      {/* Opens in a new tab */}
      <Link
        text="View documentation"
        href="https://example.com"
        target="_blank"
      />
    </div>
  );
}

export default App;
```

Omitting `target` navigates within the app. Set `target="_blank"` to open in a new tab — Link appends a trailing icon, defaults `rel` to `noopener noreferrer`, and adds an "(opens in a new tab)" announcement for screen readers.

### Inline

ai-kit-link-inline

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link-inline?file=src/App.tsx)

```tsx lines theme={null}
import { Link, Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ maxWidth: "28rem" }}>
      <Text
        text={
          <>
            Review the <Link text="account settings" href="/settings" /> before
            continuing.
          </>
        }
      />
    </div>
  );
}

export default App;
```

Link renders inline by default, so it flows naturally inside body copy built with `Text` or `Markdown`.

## Behavior

The Link responds to hover and keyboard focus, and wraps like any other inline text.

### Visual States

ai-kit-link-visual-states

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link-visual-states?file=src/App.tsx)

```tsx lines theme={null}
import { Link } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      {/* Rest */}
      <Link text="Go to dashboard" href="/dashboard" />

      {/* Hover */}
      <Link text="Go to dashboard" href="/dashboard" data-interactive="hover" />

      {/* Focus */}
      <Link
        text="Go to dashboard"
        href="/dashboard"
        data-interactive="focus-visible"
      />
    </div>
  );
}

export default App;
```

Hover shifts the link to the informative (blue) color while the underline stays as the resting affordance. Keyboard focus draws a ring around the whole link and removes the underline, since the ring itself becomes the focus affordance.

### Wrapping

ai-kit-link-wrapping

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link-wrapping?file=src/App.tsx)

```tsx lines theme={null}
import { Link } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ maxWidth: "12rem" }}>
      <Link
        text="A long link label that wraps across more than one line inside its container"
        href="/dashboard"
      />
    </div>
  );
}

export default App;
```

Long link text wraps naturally within its container, the same as any other inline text.

## Usage Guidelines

### When to Use

Use the Link when:

* **Navigating within the app** – The destination is another page or location in the product.
* **Opening a destination in a new tab** – The Link adds a trailing icon and tells screen reader users that it opens in a new tab.
* **Linking from body copy** – The link sits inline within a sentence of Text or Markdown.

### When not to use

Avoid using the Link for:

* **Triggering an action** – Use the [Button](https://anvil.servicetitan.com/docs/components/button/ai-kit.md) instead.
* **Attributing agent content to a source** – Use the [Citation](https://anvil.servicetitan.com/docs/components/citation/web.md) instead.

## Keyboard Interaction

Users can navigate and activate the Link using standard keyboard controls.

| Key | Description |
| - | - |
| Tab | Moves focus to the link |
| Enter | Activates the focused link's `href` |

## Code

**Implementation**

ai-kit-link

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Link } from "@servicetitan/anvil2-ai-kit";

function App() {
  return <Link text="Go to dashboard" href="/dashboard" />;
}

export default App;
```

## Common Examples

To use the `Link`, import it from `@servicetitan/anvil2-ai-kit` and pass a required `text` prop. The kit forbids `children`; all content flows through typed props.

```tsx theme={null}
import { Link } from "@servicetitan/anvil2-ai-kit";

function ExampleComponent() {
  return <Link href="/dashboard" text="Go to dashboard" />;
}
```

Without an `href`, React Aria renders a `<span role="link">`. For client-side routing, configure a React Aria `RouterProvider` at the app root so `href` is router-aware.

### New tab

Set `target="_blank"` to open in a new tab. `Link` appends an open-in-new icon, defaults `rel` to `"noopener noreferrer"` unless you pass `rel`, and announces "(opens in a new tab)" to assistive technology.

ai-kit-link-target

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link-target?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Link } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      {/* Same-page navigation (default) */}
      <Link text="Go to dashboard" href="/dashboard" />

      {/* Opens in a new tab */}
      <Link
        text="View documentation"
        href="https://example.com"
        target="_blank"
      />
    </div>
  );
}

export default App;
```

### Inline in text

`Link` renders inline, so it wraps with surrounding copy. Nest it in `Text` through the `text` prop.

ai-kit-link-inline

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link-inline?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Link, Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ maxWidth: "28rem" }}>
      <Text
        text={
          <>
            Review the <Link text="account settings" href="/settings" /> before
            continuing.
          </>
        }
      />
    </div>
  );
}

export default App;
```

### Wrapping

Long labels wrap like any other inline text.

ai-kit-link-wrapping

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-link-wrapping?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Link } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ maxWidth: "12rem" }}>
      <Link
        text="A long link label that wraps across more than one line inside its container"
        href="/dashboard"
      />
    </div>
  );
}

export default App;
```

## Internationalization

`Link` uses the `ai-kit.link.opensInNewTab` message for the new-tab announcement. English is the default. Mount `AiKitIntlProvider` inside `CartoTheme` to switch locale or override that string without colliding with your app's react-intl context.

```tsx theme={null}
import {
  AiKitIntlProvider,
  CartoTheme,
  Link,
} from "@servicetitan/anvil2-ai-kit";

function Root() {
  return (
    <CartoTheme>
      <AiKitIntlProvider
        locale="fr-FR"
        messages={{
          "ai-kit.link.opensInNewTab": "(s'ouvre dans un nouvel onglet)",
        }}
      >
        <Link
          href="https://example.com"
          target="_blank"
          text="Help center"
        />
      </AiKitIntlProvider>
    </CartoTheme>
  );
}
```

## React Accessibility

* Every `Link` requires `text`, which is the visible label and accessible name.
* `target="_blank"` adds an "(opens in a new tab)" announcement and a presentational trailing icon.
* Users activate a focused link with Enter.

**Link Props**

```tsx theme={null}
<Link href="/dashboard" text="Go to dashboard" />
```

## `Link` Props

The `Link` accepts the following props. It also forwards remaining React Aria `Link` props except `children`, `className`, `style`, and `isDisabled`.

**text** `string` *required*

Required link text. This is the visible, clickable content and the
accessible name.

**className** `string`

Caller-supplied class name merged onto the link's recipe class.

**href** `string`

Destination URL. Without an `href`, React Aria renders a
`<span role="link">`.

**rel** `string`

Link relationship. When `target="_blank"` and `rel` is omitted or
whitespace-only, `Link` sets `"noopener noreferrer"`.

**target** `string`

Anchor target. `"_blank"` appends the open-in-new icon, applies a safe
`rel` default, and adds the screen-reader announcement.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.