Citations and Answers With Holes In
A source the user can actually check, and an answer that admits what it is missing. Both are interface problems before they are model problems.
The intent, the obvious build, and why it breaks
Every lesson starts where the work starts: someone wanted an outcome, and the first implementation that comes to mind has a problem.
How do I render an answer so that a person can tell how much of it to trust?
Someone got an answer that sounds confident. Before acting on it, they want to know where it came from and whether anything was missing when it was written.
Append a "Sources" list at the bottom with the documents that were retrieved. Users who care can look.
A list at the bottom does not say which claim came from which source, so verifying one sentence means reading every document.
- A list at the bottom does not say which claim came from which source, so verifying one sentence means reading every document.
- Retrieved is not the same as used. Listing everything retrieved implies support the answer may not have.
- A citation that does not resolve — a dead link, a document the user cannot open, a page number that is not there — is worse than no citation, because it manufactures confidence that nothing backs.
- If a tool failed, the answer is missing something, and a sources list gives no way to know that (Showing What the System Is Doing).
- Superscript numbers with no accessible name are invisible to a screen reader and unreachable by keyboard.
What is actually happening
In the browser, not in the framework.
- A citation is a claim-to-source mapping. Rendering it usefully requires the backend to emit spans, not just a document list — which is a contract decision the frontend should be pushing for (How API Shape Drives UI Complexity).
- A partial result comes from a run that completed with a failure inside it: some tool did not return, and the answer was assembled anyway (What the Frontend Owns in an Agent Product).
- Citation targets are attacker-influenceable content: the model read documents, and a retrieved document can contain a URL of someone else's choosing (A Suggestion Is Not an Authorization).
- Confidence and correctness are unrelated in generated text, so the interface cannot rely on the answer's tone to signal reliability — the interface has to supply that signal itself.
What this makes the browser do
And which of it is avoidable.
- Rendering inline citation markers, which is cheap, and resolving previews on hover or focus, which is a network request that should not fire on every pointer movement.
- Keeping source documents in memory for preview, which grows the transcript's footprint.
- Sanitizing quoted source text before rendering it, once per citation (Sanitization and Trusted HTML).
A citation the reader can actually use
The test is concrete: can a person check one specific sentence in under ten seconds, without leaving the page and without reading anything irrelevant? Most citation UIs fail that test, and they fail it in the same way — by attaching sources to the answer rather than to the claim.
semantics A button (opens a preview) or a (navigates to the source) inline in the text, with an aria-label naming the source and location. The visible label stays compact; the accessible name carries the detail.
| Tab | Moves through citation markers in reading order, like any other inline control. |
| Enter / Space | Opens the source preview. |
| Escape | Closes the preview and returns focus to the marker that opened it. |
- — The preview opens without moving focus into it until the user chooses to enter it.
- — Escape returns focus to the marker, never to the top of the answer.
- — The marker itself is never removed from the tab order to reduce clutter — that is what a compact visible label is for.
- — The marker's accessible name: "Source: Q3 financial report, page 4".
- — The preview opening, and its content as ordinary readable structure.
- — When a claim has no source: "No source available for this claim", as text.
usually broken by A superscript number with no accessible name and no interactive semantics — announced as a bare digit in the middle of a sentence, unreachable by keyboard, and impossible to act on.
Revenue grew 12% in Q3, driven mainly by enterprise renewals, and headcount was flat. Sources: - Q3 financial report - Board deck - HR summary
Revenue grew 12% in Q3 [Q3 report, p4], driven mainly by enterprise renewals [Board deck, slide 9]. Headcount was flat [HR summary, Sep]. [Q3 report, p4] > "Total revenue for the quarter was > $14.2M, up 12% year over year."
The second version lets a reader verify the one number they care about without opening anything, and makes it immediately visible if a claim has no source at all — which is the failure mode a bottom-of-page list is structurally incapable of showing.
Saying what is missing
When a tool fails and the run continues, the answer that comes out is narrower than the question asked. The interface is the only place that can communicate this, and the temptation to smooth it over is strong because a hedged answer looks worse in a demo.
It is nonetheless the right call, and it is also the cheaper one: an answer that says what it checked can be trusted where it applies, whereas an answer that quietly omits a source has to be distrusted everywhere.
| Trigger | Symptom | Cause | Response |
|---|---|---|---|
| A retrieval tool returned nothing | Confident answer with no support | The model answered from general knowledge and the UI rendered it identically | Mark the answer as unsourced and say the search returned nothing. |
| One of three tools failed | Answer omits a whole dimension silently | Failure was handled server-side and never reached the UI | Surface the failed step and scope the claim to what was checked (Showing What the System Is Doing). |
| Cited document is not readable by this user | Citation link 403s | Retrieval was not scoped to the user's permissions | Filter server-side by the caller's access; never cite what the caller cannot open (Authorization-Aware UI). |
| Answer truncated mid-sentence | Looks like a complete but oddly short answer | No terminal state distinguishing truncated from complete | Render truncated distinctly and offer continuation (Streaming a Response Without Melting the Device). |
| Preview requested on every hover | A burst of requests as the pointer crosses the answer | No debounce, no dedupe, no cancellation | Debounce, dedupe by source id, cancel on pointer-out (Five Components, One Request). |
How to build it
Most important first.
- Attach citations to claims, inline, not to the answer as a whole. The unit of verification is a sentence.
- Make a citation a real link or button — reachable by keyboard, with an accessible name that says what it points to, not "1".
- Show enough of the source that the user can judge relevance without leaving: a quoted span beats a title.
- Distinguish retrieved from used. If the answer did not draw on a document, do not present it as support.
- State the gap when a tool failed, next to the claim it would have supported, and scope the answer to what was verified (Showing What the System Is Doing).
- Never fabricate a citation shape the backend cannot fill. An interface that always shows a source will show a wrong one rather than none.
Keyboard, focus, semantics, announcement
A required field on every lesson in this domain, not a section added when there is room.
- A citation marker must be a real interactive element with an accessible name describing the target — "Source: Q3 revenue report, page 4" — not a superscript number that a screen reader reads as a bare digit (Semantics Before ARIA).
- Inline markers interrupt reading flow when they are announced verbosely. Keep the visible marker compact and put the description in the accessible name, so visual and non-visual readers each get an appropriate density.
- A hover preview must also open on keyboard focus, be dismissible with Escape, and not trap focus — a tooltip pattern, with all the obligations that carries (Accessible Component Patterns).
- A missing-source or degraded-answer notice must be part of the text content, not a colour or an icon, so it reaches everyone (Contrast, Colour and Motion).
- Marking up the answer with real structure — headings, lists, paragraphs — is what lets a screen-reader user skim it. A wall of generated text with no structure is technically readable and practically not.
What can go wrong
- Citations that all point at the same document because the mapping was approximate, training users to ignore them.
- A preview that fires a request on every hover, producing a request storm across a long answer (Five Components, One Request).
- A cited document the user is not authorized to open, which leaks its existence and title (Authorization-Aware UI).
- An answer rendered identically whether or not a source was available, so degradation is undetectable.
- Citation markers that break text selection and copy, so quoting the answer elsewhere produces "[1][2]" noise.
- Citation events can arrive after the text they annotate, so markers must be attachable to already-rendered spans rather than assumed to arrive inline.
- A preview request can resolve after the user has moved on, and must not overwrite a newer one (Out-of-Order Responses).
- A cited URL came from a document the agent read, so it can be attacker-chosen. Validate the scheme, show the real destination, and never auto-load anything from it (Cross-Site Scripting).
- Loading a preview image or favicon from a cited host discloses to that host that your user opened the answer (Third-Party Scripts and the Supply Chain).
- Quoted source text is untrusted content and must be sanitized before rendering, exactly like the answer itself.
- Citing a document reveals that it exists and what it is called. Authorization for the citation is the same question as authorization for the document (What the Frontend Is Responsible For in Auth).
- "Citations prove the answer is right." They show what the answer drew on. A correctly cited source can still be misread by the model, which is exactly why the user needs to be able to check it.
- "Listing retrieved documents is citing." Retrieval is not use, and presenting it as such implies support that may not exist.
- "Users do not read citations." They read them when a decision depends on it — which is the moment the interface has to work.
- "Partial answers should be hidden." A clearly-scoped partial answer is often exactly what the user needs; a partial answer presented as complete is the actual harm.
Measuring it, and what changes in the field
- Citation click-through: nobody following citations means either they are not needed or, more likely, they are not usable.
- How often an answer is rendered in a degraded state, which is a product health metric that only the client can compute.
- Preview request volume per answer, to catch a hover handler that is firing far more than it should.
- On a small screen, inline citations compete for space with the text; a compact marker with an accessible name handles both.
- On a slow network, previews must be deferred and cancellable or they compete with the stream itself (Cancelling a Request Nobody Is Waiting For).
- In a long answer, citation density matters — one per sentence is unreadable, one per answer is unverifiable.
- Inline citations make verification possible and make the text denser and harder to read. Compact markers with rich accessible names are the compromise that serves both.
- Showing quoted source text is far more useful than a title and costs layout space, memory and a sanitization pass.
- Admitting a gap reduces apparent confidence, which is the correct trade: an answer that overstates what it checked is worse than one that is honestly narrower.
Where this applies
Frontend advice ages badly and fragments across engines. These labels say what each claim is specific to, and where a different browser, device or framework would differ.
- GENERALThe claim-to-source mapping and the obligation to make a citation checkable are product and interface constraints, independent of model or retrieval implementation.
- FRAMEWORK-SPECIFICAttaching markers to spans inside streamed text is straightforward where the renderer keeps stable node identity across updates, and awkward where each update replaces the block — in the latter case you need to render citations from the same source of truth as the text rather than patching the DOM after the fact (Node Identity Across Updates).
Where the depth lives
This domain teaches the browser-side mechanism and hands the rest off.
- — Testing & Reliability Engineering — asserting that a degraded run renders as degraded is the test that stops this regressing, and it is easy to forget because the happy path looks identical.