# Sources

Sources [#sources]

The **Sources** primitives render retrieval citations from local RAG results (e.g. `useSemanticSearch`). `Sources` is the collapsible container; `SourcesTrigger` shows the count; each `Source` renders a favicon/title/excerpt chip and a 0–1 relevance score. An optional tabbed layout switches between Web / Images / News-style result variants. All favicons/images come from already-stored local metadata — there is no remote unfurl.

Preview [#preview]

```tsx
'use client';

/**
 * @file sources-demo.tsx
 * @description Docs preview for `Sources`. Collapsible list of local RAG
 * citations with relevance scores; all metadata is local (no network unfurl).
 */
import {
  Source,
  Sources,
  SourcesContent,
  SourcesTrigger,
  type SourceItem,
} from '@/components/sources';

const SOURCES: SourceItem[] = [
  {
    id: '1',
    title: 'Local-first architecture',
    excerpt: 'Models are cached on-device; subsequent runs work fully offline.',
    score: 0.92,
  },
  {
    id: '2',
    title: 'WebGPU acceleration',
    excerpt: 'GPU compute shaders speed up vector distance and inference.',
    score: 0.81,
  },
  {
    id: '3',
    title: 'Privacy guarantees',
    excerpt: 'Data never leaves the device - no telemetry, no API keys.',
    score: 0.74,
  },
];

export default function SourcesDemo() {
  return (
    <div className="w-full max-w-xl">
      <Sources defaultOpen>
        <SourcesTrigger count={SOURCES.length} />
        <SourcesContent>
          {SOURCES.map((s) => (
            <Source key={s.id} source={s} />
          ))}
        </SourcesContent>
      </Sources>
    </div>
  );
}
```

Installation [#installation]

```bash
npx shadcn@latest add @localmode/ui/conversation/sources
```

Data source & dependencies [#data-source--dependencies]

**Data source:** renders a list of `{ href, title }` you pass — works with any backend. Recommended producer: `useSemanticSearch` from `@localmode/react` (on-device). See [Use with the Vercel AI SDK](/docs/use-with-ai-sdk#source-parts--sources).

* `clsx` + `tailwind-merge` — via the shared `cn()` util (installed automatically as a registry dependency)

Files installed [#files-installed]

* `sources.tsx` — `Sources`, `SourcesTrigger`, `SourcesContent`, `Source`
* `lib/utils.ts` — the `cn()` helper (if not already present)

Props [#props]

**Source**

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `source` | `object` | — | **Required.** The source to render. |

Examples [#examples]

From local search results [#from-local-search-results]

```tsx
import { Source, Sources, SourcesContent, SourcesTrigger } from '@/components/sources';

<Sources>
  <SourcesTrigger count={results.length} />
  <SourcesContent>
    {results.map((r) => (
      <Source key={r.id} source={{ id: r.id, title: r.metadata.title, excerpt: r.text, score: r.score }} />
    ))}
  </SourcesContent>
</Sources>
```

Customization [#customization]

Enable the tabbed layout by passing `tabbed` + `sources` to `SourcesContent`. Favicons render from `faviconUrl` in your stored metadata — leave it unset for the default globe icon.

These primitives are presentational and hook-driven: they render props and emit callbacks, holding only local view state. The orchestration state (e.g. `useSemanticSearch`) lives in your app. Every surface uses shadcn/ui CSS-variable utilities, so it inherits your theme — restyle the copied file freely.