Figma UI kit
Domain and AI

AI indicators and thermal aura

v1.2.1

Mark where AI produced or is producing something, with one warm visual identity.

Quick usage

Import the shared component; never copy its markup into a feature. The Web TSX tab beside the live stage has a complete, working example.

import Chip from '@/shared/components/Chip';
import AiSparkle from '@/shared/components/AiSparkle';
import { AiEmptyGreeting } from '@/shared/components/AiChat/AiEmptyGreeting';

Live stage and code

The live component and its controls on the left, the code on the right; change a control and the code follows: Web TSX (the component in a working example), Tailwind and HTML (the markup it renders, with its data attributes), React Native, SwiftUI and Jetpack Compose. The header theme switch drives every stage.

Props

Read from the component's source when the docs build: names and defaults from its signature, types and descriptions from its JSDoc. A blank type means the prop has no JSDoc yet.

Chip

PropTypeDefaultDescription
tone'neutral'|'success'|'warning'|'error'|'info'|'violet'|'primary'|'outline'|'ai''neutral'The CONDITION being reported, not a colour choice (sec.13). `outline` is for a tag that names a thing rather than a state, so it spends no status hue.
size'sm'|'md'|'lg''sm'The DENSITY of the surface, not the importance of the text: `sm` (20px) in table rows and grids, `md` (24px) on cards and panel headers, `lg` (32px) in inline banners only. The label is 12px at all three.
variant'chip'|'badge''chip'`badge` is the counter (Inter, tabular figures), one rung tighter than a chip at every tier (18 / 22 / 30).
dotbooleanfalseThe 5px leading dot, in the chip's own colour.
iconReact.ReactNodenullA leading glyph instead of the dot. Sized by the caller, because Phosphor takes size as a prop; 12px is the tier for a 20px chip.
trailingIconReact.ReactNodenullA glyph after the label, for a pressable chip that goes somewhere (an arrow to an external file). Same sizing as `icon`.
countnumber|stringnullA tally after the label ("Fasteners 4"). Rendered as a sibling so the chip's own gap spaces it, in the data face at the chip's own size. Do NOT nest a <Chip variant="badge"> inside a chip to get this.
selectedbooleanfalseThe chosen one in a row of filter chips. Steps up the surface ladder rather than taking a status hue: a filter you picked is not a condition the thing is in.
onClick() => void-Renders a <button> and adds the mandatory 44x44 boundary. The chip does NOT grow to 28px - see the ds-chip note in the CSS.
hrefstring-Renders an <a> instead, with the same boundary and hover. For a chip that GOES somewhere - a mailto, an external file - where a <button> with a programmatic navigation would lose the middle-click, the copy-link and the status bar a real link gives for free.
classNamestring--
childrenReact.ReactNode--
...rest--Any other prop is passed through to the root element.

Source: frontend/src/shared/components/Chip/Chip.js

AiSparkle

PropTypeDefaultDescription
sizenumber20Rendered px. 20 in the desktop cluster, 16 and 14 inline.
tone'current'|'thermal''current'Paint. See above.
classNamestring''Hook for the host's hover/press treatment.
...rest--Any other prop is passed through to the root element.

Source: frontend/src/shared/components/AiSparkle/AiSparkle.js

AiEmptyGreeting

PropTypeDefaultDescription
titlestring--
hintReact.ReactNodenull-
promptsstring[][]-
onPick(prompt: string) => void--
disabledbooleanfalse-

Source: frontend/src/shared/components/AiChat/AiEmptyGreeting.js

DOM contract

What the rendered element carries: the data attributes its styles key on, its roles and ARIA, its focus style, and whether its stylesheet draws the 44px hit boundary. Also read from the source.

Chip

Data attributesdata-selecteddata-sizedata-tonedata-variant
RolesNative element semantics only
ARIANone set by the component
FocusStyles :focus-visible in its own stylesheet
44px hit boundaryYes: a ::after in Chip.module.css

AiSparkle

Data attributesdata-ds
RolesNative element semantics only
ARIANone set by the component
FocusNo :focus-visible rule of its own
44px hit boundaryNot a pressable root

AiEmptyGreeting

Data attributesNone set by the component
RolesNative element semantics only
ARIANone set by the component
FocusStyles :focus-visible in its own stylesheet
44px hit boundaryYes: a ::after in AiEmptyGreeting.module.css

Accessibility and touch

The indicator is metadata; any control beside it has its own target.

AI indicators and thermal aura is passive: it reports a condition and is not pressed, so it has no hit boundary. If a design makes it pressable, it gains the 44 by 44 boundary and is marked /* ds-chip: why */.

Human in the loop

An AI mark is a claim about who wrote a value, so it has to stay true. These rules come from FRONTEND_PR_COMPLIANCE.md sec.16.1. Try the first one on the stage above: edit the vendor.

  • Provenance clears the moment a person edits the value. The pill goes and the field edge returns to the standard focus, on --duration-instant, border and shadow only. There is no undo to the AI value and no confirmation prompt: a pill that survives a human edit claims the machine wrote something it did not.
  • In code, Input takes origin="ai" or "human", and the caller flips it to "human" on the first edit. Nothing clears it automatically, so every AI-filled field must do this.
  • Confidence is an affordance, never a gate. A confidence value never skips or short-circuits a human review step; high confidence is not approval.
  • Confidence takes warm sand and terracotta, never a status hue. A green "high confidence" chip reads as verified, which is the one claim a confidence score cannot make.
  • AI output is reviewed at the HITL review step, never in chat. An agent can name a match and describe an action, but never executes it from chat.

Do and avoid

Do
Do: mark a value a model wrote with the AI pill, until a person edits it.
Avoid
AILead time 3 weeks
Avoid: a flat cyan box. Cyan is the info status hue, so it claims a condition, and a square box reads as a control.

Rules and constraints

Use it for

  • AI-generated values, the assistant, a running pipeline.
  • The AI pill (Chip tone="ai") on any value a model wrote, until a person edits it.

Avoid

  • Never an ambient effect that changes size: a growing layer drags its edge (gate C14).
  • Never a raw id in a status pill.

Constraints

  • The four-point star, sand to terracotta; motion stops under reduced motion.
  • Provenance clears the moment a person edits the value: the pill goes and the field edge returns to the standard focus, on --duration-instant. No undo to the AI value, no confirmation. Input takes origin; the caller flips it to human on the first edit.

More in Domain and AI