Components/InlineCitation

InlineCitation

A source-reference chip that sits inside prose and emits rather than navigating.

VerifiedSince 0.3.9

InlineCitation

Basic Usage

Inline Citation

The chip is typeset with the text around it: 18px tall, mono face, nudged up a pixel so its cap height lines up with the prose instead of sitting on the baseline.

Loading demo...

Citations in a Streaming Answer

The citation lands when the prose reaches it, which is exactly what the pop-in entrance is for. The whole sequence is orchestrated by the demo; the component only ever renders one chip.

Streaming answer

Word-by-word reveal, an inline citation, stacked sources and a follow-up list.

Loading demo...

API

Props

NameTypeDefaultDescription
sourceAiSourceItemThe reference, shaped { id, url, title?, favicon? }. Required.
labelstringChip text. Falls back to source.title, then the hostname of url with www. stripped.
appearbooleantruePlays the entrance pop. Set false when re-rendering a settled answer so a paragraph of citations does not re-pop.

When url cannot be parsed by URL, the fallback chain ends at the raw url string rather than rendering an empty chip.

Events

NamePayloadDescription
open(source: AiSourceItem)Emitted on click. The default navigation is prevented; opening is the host's call.

Slots

NameScopeDescription
default{ source, label }Replaces the chip text, rich content included.
icon{ source }Replaces the leading favicon — a hand-drawn category mark, for instance.

Interaction Contract

  • The link never navigates on its own. It renders a real <a href>, but a click calls preventDefault() and emits open. This is mandatory inside an Electron renderer — walking the whole app away is the last thing a citation in body text should do.
  • The href stays in the DOM, so the browser's own "open in new tab" and "copy link address" menus keep working.
  • A favicon that fails to load is recorded and stops rendering; the chip degrades to text rather than holding a broken-image placeholder.
  • The icon carries alt="" and aria-hidden; the accessible name comes from the chip text.
  • The chip sits in the text flow with vertical-align: middle plus a 1px lift. Line height belongs to the surrounding paragraph — the component sets none of its own.
  • The entrance plays once, on mount. appear is a render-time decision; flipping it later does not replay anything.

Best Practices

  • Listen for open, or clicking a citation does nothing at all.
  • Keep it to two or three citations per paragraph. Chips are visually heavier than words, and a dense run reads as a list rather than a sentence.
  • Leaving label empty is usually better: the hostname fallback tells the reader where a claim came from, and a custom label tends to hide that.
  • Use stable source.id values in streaming surfaces. The failed-icon record is per instance, so stable data is what stops a bad favicon being retried as nodes are reused.
  • When you want the source list at the end of an answer rather than a reference inside it, reach for TxSources. The two are complementary and often appear together.

Source

  • Component source: packages/tuffex/packages/components/src/inline-citation/src/TxInlineCitation.vue.
  • Types: packages/tuffex/packages/components/src/inline-citation/src/types.ts.
  • Tested behaviour: packages/tuffex/packages/components/src/inline-citation/__tests__/inline-citation.test.ts (7 cases) covers the hostname fallback and www. stripping, the label / title precedence, the unparseable-URL fallback, click emitting open instead of navigating, the favicon disappearing after a load failure, and appear gating the entrance class.
  • Adapted from Beautiful UI (https://www.beautifului.dev), © 2026 Shane Levine, MIT.
查看源码
packages/tuffex/packages/components/src/inline-citation/index.ts