Skip to content
Elements

Inline citation

Numbered references inside a sentence, each with a hover preview of its source.

Optimistic updates keep the thread responsive while the server confirms the write. The store already exposes a consistent snapshot for every subscriber, so no extra reconciliation pass is needed.

fig. 01

Installation

Install manually
npx shadcn@latest add "@assistant-ui/elements-inline-citation"
First time? Set up a runtime

Runtime components read their state from an assistant-ui runtime. Add one to an existing project:

npx assistant-ui@latest init

Then wrap your app in a runtime provider:

import { AssistantRuntimeProvider } from "@assistant-ui/react";
import { useChatRuntime, AssistantChatTransport } from "@assistant-ui/ai-sdk";

export default function App() {
  const runtime = useChatRuntime({
    transport: new AssistantChatTransport({ api: "/api/chat" }),
  });

  return (
    <AssistantRuntimeProvider runtime={runtime}>
      {/* your components */}
    </AssistantRuntimeProvider>
  );
}

The installation guide covers new projects, templates, and API routes.

Wrap the prose in InlineCitation, then place a Citation marker beside each claim it supports. Hovering or focusing a marker opens a compact preview with the source details.

Getting started

When a runtime receives source parts or a tool result, map each source to a Citation at the position it belongs in the rendered answer. The element does not infer offsets from streamed text.

Map source parts

app/answer.tsx
"use client";

import {
  Citation,
  InlineCitation,
  type Source,
} from "@/components/assistant-ui/elements/inline-citation";

type AnswerPart =
  | { type: "text"; text: string }
  | { type: "source"; id: string; index: number; source: Source };

export function Answer({ parts }: { parts: readonly AnswerPart[] }) {
  return (
    <InlineCitation>
      {parts.map((part) =>
        part.type === "text" ? (
          part.text
        ) : (
          <Citation key={part.id} index={part.index} source={part.source} />
        ),
      )}
    </InlineCitation>
  );
}

Keep the text and source parts in display order. index starts at zero, while the marker shows the reader index + 1.

Map a tool result

Convert a completed tool result to the same parts before rendering it. The source URL supplies a displayed domain when domain is absent:

const parts: AnswerPart[] = [
  { type: "text", text: "The latest release supports structured outputs" },
  ...result.sources.map((source, index) => ({
    type: "source" as const,
    id: source.id,
    index,
    source: {
      title: source.title,
      snippet: source.summary,
      url: source.url,
      publishedAt: source.publishedAt,
    },
  })),
  { type: "text", text: "." },
];

Anatomy

<InlineCitation>
  A supported claim
  <Citation index={0} source={source} />.
</InlineCitation>

InlineCitation is the paragraph and forwards its p props. Each Citation is a button marker that opens its own preview card. The marker's accessible name includes the source title, so the numbered label never has to carry the source context alone.

Examples

Include publication details

publishedAt is formatted as a month and year when it is a valid date. A safe url adds an Open source link that opens in a new tab. An invalid date or unsafe URL is omitted from the preview.

const SOURCE: Source = {
  title: "React useSyncExternalStore reference",
  snippet: "Subscribes to an external store with a consistent snapshot.",
  url: "https://react.dev/reference/react/useSyncExternalStore",
  publishedAt: "2024-12-05T12:00:00.000Z",
};

Give the paragraph more room

The default paragraph stays compact. Pass className or any other paragraph prop when the surrounding layout needs a different width or label:

<InlineCitation className="max-w-none" aria-label="Sources for the answer">
  The deployment completed successfully
  <Citation index={0} source={SOURCE} />.
</InlineCitation>

API reference

Runtime mapping

ValueTypeDescription
Text part{ type: "text"; text: string }Renders directly inside InlineCitation.
Source part{ type: "source"; id: string; index: number; source: Source }Renders a keyed Citation at that point in the prose.
Tool resultApplication-definedConvert source records from a completed result to source parts before rendering.