PixelDosa UI

AI Context / Provenance Surface

A collapsed-by-default "Why this?" disclosure for an AI-produced value's explanation, sources, and model metadata — works with no chat thread required.

Acme Robotics, Inc.

Matched based on the company's domain and two similar records already in your workspace.

  1. 1.acme-robotics.com
  2. 2.Similar record: Acme ManufacturingSame domain root, added 3 weeks ago.

claude-opus

Installation

bash
npx shadcn@latest add @pixeldosa/ai-context-surface

Requires `cn` at `@/lib/utils`. `generatedAt` is formatted internally (relative within 24 hours via Intl.RelativeTimeFormat, an absolute locale date otherwise) rather than left to the consumer, since every consumer would otherwise reimplement the same relative-or-absolute decision. Renders `null` entirely when none of `explanation`/`sources`/`model`/`generatedAt` are supplied — a trigger with nothing behind it is worse than no component.

Usage

import { AIContextSurface } from "@/components/ui/ai-context-surface";

<AIContextSurface
  explanation="Matched based on similar historical records with the same domain."
  sources={[{ label: "acme-robotics.com", url: "https://acme-robotics.com" }]}
  model="claude-opus"
  generatedAt={new Date()}
/>

Every prop is optional. If none are supplied, the component renders nothing — a trigger with an empty panel behind it would be worse than no component at all.

<AIContextSurface
  sources={[
    { label: "Similar record: Acme Manufacturing", snippet: "Same domain root, added 3 weeks ago." },
  ]}
/>

A source only needs a label; url and snippet are both optional and independent — a source can have a link, a snippet, both, or neither.

Features

  • Quiet until asked for. Collapsed by default, so provenance never competes with the value it explains — this is the reference implementation of DESIGN.md §4's "quiet until asked for" instinct.
  • Renders nothing when it has nothing. Every prop is optional; with none supplied the component returns null rather than offering a trigger with an empty panel.
  • Evidence over decoration — sources carry an optional link and an optional snippet, independently, so you can show the actual retrieved text rather than just asserting a source exists.
  • A real disclosure, with aria-expanded/aria-controls wired correctly, not a custom widget that merely looks like one.
  • No chat thread required — it attaches to a single value anywhere in ordinary product UI.

Variants

Explanation only — the minimum useful surface:

Matched on the same domain root as three existing records, added within the last month.

With sources and model metadata

Matched based on similar historical records with the same domain.

  1. 1.acme-robotics.com
  2. 2.Similar record: Acme ManufacturingSame domain root, added 3 weeks ago.

claude-opus

A custom trigger label

triggerLabel is both the visible and the accessible label, so it should read as a question the user actually has.

  1. 1.Q3 pipeline exportRow 148, imported 2 weeks ago.

Props

PropTypeDefaultDescription
explanationstring—Plain-language reasoning, shown first.
sources{ label: string; url?: string; snippet?: string }[]—Rendered as a numbered list.
modelstring—Shown in the metadata footer line.
generatedAtstring | Date—Formatted internally (relative within 24h, absolute otherwise).
triggerLabelstring"Why this?"Visible and accessible label for the collapsed trigger.

Accessibility

  • A real disclosure: aria-expanded and aria-controls wired correctly, not a custom widget that only looks like one.
  • Panel content is normal reading-order text, not a floating overlay, so it reflows naturally at any width.
  • Under prefers-reduced-motion, the expand/collapse becomes instant; aria-expanded communicates the state to assistive technology regardless of any icon animation.

When not to use

A full chat/conversation transcript is out of this system's scope entirely. A single short provenance caption for one value already has a home — Smart Field's own inline provenance prop — use that instead of this heavier disclosure for a one-line via {source} caption.

why it's built this way

Engineering Notes

Deliberately a disclosure (collapsed by default), not an always-visible panel: provenance detail is important to have available but wrong to force onto every view, since it would compete with the actual content for attention the moment it's always open — the same restraint Smart Field's inline `via {provenance}` caption already established, applied here at a larger, richer scale. Folds three previously-separate roadmap ideas (Citation Card, Source Viewer, Thinking Indicator) into one component because all three share the same real constraint this system cares about: working with zero chat thread present, unlike Vercel AI Elements' `Reasoning`/citation components, which are chat-message-scoped and excellent at that job specifically — competing with them there would be a bad trade, per the roadmap's own Reconciliation table. Timestamp formatting uses native `Intl.RelativeTimeFormat` rather than a date-formatting dependency, keeping this primitive dependency-free like every other component in the registry.

how it moves, and when it doesn't

Motion Notes

Expand/collapse reuses the same CSS grid-template-rows (0fr to 1fr) technique Smart Field's proposal panel and Diff Accept's conflict banner already use — a proven, token-free way to animate a height that depends on variable content, on --pd-duration-fast/--pd-ease-standard. The trigger's chevron rotates 90 degrees on open using --pd-duration-instant, matching Button's press-feedback timing, since it's an immediate state confirmation rather than content arriving. Under prefers-reduced-motion, both the panel's height transition and the chevron rotation drop via motion-reduce:transition-none, leaving the open/closed state instant but fully legible — aria-expanded already communicates the state to assistive technology regardless of the icon's rotation.