Citations
Free · MITInline numbered source chips that open a spring hover card with title, domain, snippet and date, a CitedText helper that turns [1] markers into chips, and a sources list whose row lights up when its chip is hovered.
Installation
$ npx shadcn@latest add https://goodui.dev/r/citations.jsonThe file lands in components/goodui/citations.tsx and is yours to edit. With the @goodui registry added, npx shadcn@latest add @goodui/citations works too.
Usage
import { Citations, CitedText, SourceList } from "@/components/goodui/citations"
<Citations sources={[
{ n: 1, title: "Deposits and no-show fees", url: "https://help.example.com/deposits", snippet: "New clients pay a 20% deposit…", date: "Oct 2026" },
{ n: 2, title: "No-show report, September–October", url: "https://reports.example.com/no-shows", date: "Nov 1, 2026" },
]}>
<p><CitedText text="No-shows fell from 9 to 3 [2] after the deposit rule [1]." /></p>
<SourceList limit={3} />
</Citations>When to use
- RAG or search-grounded answers where each claim points at a document, page or record.
- Answers that quote internal docs, policies or reports: the card shows the snippet without leaving the chat.
- A sources list under the answer, with the matching row lighting up when a chip is hovered.
- Academic footnotes in long documents: a footnote list at the end of the page reads better.
- A single link: a plain anchor.
| If you need | Use |
|---|---|
| Model output with [1] markers | <CitedText text={answer} /> |
| Hand-placed chips in JSX | <Cite n={2} /> anywhere inside <Citations> |
| Card below the chip | side="bottom" (it flips automatically near the top of the viewport) |
| Short list with Show all | <SourceList limit={3} /> |
Examples
Chips in your own markup
<p>Deposits are refundable for 24 hours<Cite n={1} />, and reminders go out twice<Cite n={3} />.</p>Favicon per source
{ n: 1, title: "Stripe docs", url: "https://docs.stripe.com/payments", icon: <img src="/favicons/stripe.png" alt="" /> }API reference
Citations
| Prop | Type | Default |
|---|---|---|
| sources* | CitationSource[] | — |
| labels Text for built-in controls and screen readers; pass translations here. | Partial<CitationsLabels> | — |
Also accepts every <div> attribute.
Cite
| Prop | Type | Default |
|---|---|---|
| n* Source number, matching a source's `n`. | number | — |
| side Where the hover card opens. | "top" | "bottom" | "top" |
Also accepts every <element> attribute.
CitedText
| Prop | Type | Default |
|---|---|---|
| text* Text with "[1]" style markers. | string | — |
Also accepts every <span> attribute.
SourceList
| Prop | Type | Default |
|---|---|---|
| limit Rows shown before a "Show all" button. | number | 3 |
| hideTitle Hide the "Sources" heading. | boolean | false |
Also accepts every <section> attribute.
Accessibility
| Tab | Moves between chips; focusing a chip opens its card. |
| Enter | Opens the source URL in a new tab (chips with a URL are links); on a chip without a URL, Enter or Space opens the card. |
| Escape | Closes the card. |
- Each chip is a link (new tab, rel="noreferrer") when the source has a URL, otherwise a <button>; both are labelled "Source n: title" and described by the open card (role="tooltip") through aria-describedby.
- The card opens on hover (mouse only) and focus, and closes on blur, Escape, scroll or resize.
- The sources list is an ordered list; rows with a URL are links named by their title, domain and date, with an "Open source" tooltip.
- Built-in strings go through the labels prop for translation.
Motion
- The card scales from 0.94 at the chip's edge on a spring (stiffness 560, damping 32) and fades out in 120 ms; it is positioned fixed and clamped to the viewport.
- Source rows spring into place when the list expands; the hovered chip's row and number tile change color.
- Reduced motion: the card and rows fade only.
Notes for AI
Coding agents read these rules through MCP and llms.txt, or paste this page with Copy page.
- Wrap the answer and the list in <Citations sources>. Source numbers (n) are what CitedText matches: [2] renders source n=2.
- CitedText only understands [n] markers. Convert other formats (【1】, ^1) before passing the text.
- A chip whose number has no matching source renders nothing.
- domain is derived from url when omitted; snippet, date and icon are optional.
FAQ
Why is the card positioned fixed?
So it can escape chat containers with overflow hidden or scrolling. It closes on scroll instead of following the chip.
Why is a chip sometimes a link and sometimes a button?
With a URL it is a real link, so middle-click, copy link and screen readers' link lists work. Without one it is a button that only opens the card.
Related
User, assistant and system messages with avatars, grouping, a hover actions row (copy, good/bad, retry, edit), markdown-ish rendering of lists, quotes and fenced code into CodeBlocks, and a blinking caret while the answer streams.
Dark, light, tone, glass and neo tooltips with sizes, shapes, shadows and an optional arrow; twelve placements that flip and shift at the screen edge, scale, fade, slide or spring entrances, rich title + keyboard-shortcut content, delay groups that open instantly after the first, follow-cursor for charts and touch long-press.
Anchored popover with an arrow in default, soft, glass, neo and inverted surfaces, tones, sizes, radii and shadows; side and align that flip and shift to stay on screen, match-trigger-width, scale, fade, slide or spring entrances, header, close button and footer slots, and modal (focus trapped) or non-modal (Tab flows back to the page) behavior, shown as a date filter, share menu, switcher and inline note form.
Inline link with seven underline styles (static, slide-in, grow from center, marker sweep, nudging arrow), line decorations, tones, leading icons and automatic external-link handling. Works with next/link via as.