Agent docs

FieldChip

The name of a data field or source file as a small pill: a label, never a value.

The name of a data field or a source file, wherever one is shown: a small pill that reads as a label, never a value, so a reader never mistakes the two. The third of the kit's three small-tag species: StatusPill/StatusDot communicate STATE, Chip communicates SELECTION, FieldChip communicates NAMING (docs/design-language/03-status-language.md §A1, the same line quoted in chip.md and status.md).

The canon behind it. docs/design-language/03-status-language.md §A1 (03-status-language.md:13, the three-species line quoted above) and docs/design-language/01-foundations.md §A1 (01-foundations.md:13, only the semantic layer knows about themes, the exact rule this component's own dark-mode bug taught).

When to reach for it#

Naming a schema field key (partType, brand, upc) or a source file, anywhere that name appears as a label rather than as content. Do not reach for it to show a record's status, that is StatusPill/StatusDot, and not for a selectable or removable value, that is Chip.

Contract#

FieldChip's own contract is deliberately narrow, much narrower than Chip's: there is no size, variant, Icon, selected, or removable mode.

  • children: the field key text, or any node.
  • tone: FieldChipTone, a two-way union. "field" (default) is a quiet neutral pill (bg-base-200 text-base-content/70); "file" is a warm pill (bg-warning/10 text-warning), because "a file is a thing you can open, so it reads as its own kind" (field-chip.tsx:22-23).
  • onClick: when given, the chip renders as a real <button>; when omitted, a plain non-interactive <span>.
  • className.

Both tones use theme tokens rather than raw palette literals on purpose: an earlier version used raw slate/amber colors that never flipped with the theme and drew white pills in dark mode (field-chip.tsx:19-21).

Types are exported from field-chip.tsx itself rather than a sibling .types.ts (FieldChipProps, FieldChipTone, index.ts); this is the one component in this batch that does not follow the kit's usual file split.

App-local wrappers#

Because the contract is this narrow, speedway ships two app-local components that wrap FieldChip rather than extending it:

  • FileChip (speedway/app/components/file-chip.tsx), built on tone="file": adds a leading file icon, a trailing external-link icon, click-to-preview wiring through a modal hook, and a custom midTruncate that keeps a filename's start and extension and ellipsizes the middle, because CSS end-truncation eats exactly the part that tells two vendor exports apart (file-chip.tsx:74-80). Without a resolvable id it degrades to a plain non-clickable chip that "still reads correctly; it simply cannot be opened" (file-chip.tsx:29-30).
  • WrappingFieldChip (speedway/app/components/wrapping-field-chip.tsx): wraps a plain tone="field" chip in an inner <span className="min-w-0 break-words"> so long field names wrap inside a table-fixed column instead of overflowing into the next one. The inner span is load-bearing: FieldChip is inline-flex, so a bare string child becomes an anonymous flex item whose default min-width: auto refuses to shrink below its longest unbreakable word; only a real element you can put min-w-0 on lets the wrap actually happen (wrapping-field-chip.tsx:11-17).

Both are the shipped pattern for extending FieldChip's behavior; reach for one of them, or build a sibling the same way, before adding props to FieldChip itself.

Plain, unwrapped <FieldChip>{value}</FieldChip> with the default field tone is also common and legitimate: speedway/app/components/content-fields.tsx:121, speedway/app/components/ProductItem.tsx:336, speedway/app/routes/workspaces/jobs/run.tsx:319, speedway/app/routes/workspaces/review/log.tsx:517, walmart-mvp/frontend/src/features/parts/PartPreviewModal.tsx:221,266,623.

Sanctioned combinations#

CombinationProducesWhere usedWhy
Plain <FieldChip>{key}</FieldChip>, default field tone, no onClickA read-only field-name label in a key/value row or table cellcontent-fields.tsx:121, ProductItem.tsx:336, PartPreviewModal.tsx:221The field name is informational only; nothing to click
tone="file" plus an onClick that opens a preview modal, via the app-local FileChipA filename that opens in place instead of navigating awayfile-chip.tsx:33-72Per the source comment, leaving the part you are reading to go look at a column header is a bad trade (file-chip.tsx:28-29)
className="min-w-0" plus an inner min-w-0 break-words span, via the app-local WrappingFieldChipA field-name chip that wraps instead of overflowing a fixed-width table columnwrapping-field-chip.tsxPIM field names run long and unbroken; a table-fixed grid cannot let one chip paint over the next column

Banned combinations#

Do not use FieldChip to show a record's state (that is StatusPill / StatusDot) or a selectable, removable value (that is Chip). The three small-tag species are never interchangeable (docs/design-language/03-status-language.md:13); a field name in a status tone tells the reader the field is a state, which is the confusion the species exist to prevent.

Do not add size, variant, Icon, or a removable mode to FieldChip to get a richer chip. The narrow contract is deliberate; the shipped way to extend behaviour is an app-local wrapper (FileChip, WrappingFieldChip, above), or Chip when the thing is a value after all.

Do not put a raw palette colour on a chip tone. Both tones read theme tokens because an earlier version used raw slate/amber that never flipped with the theme and drew white pills in dark mode (field-chip.tsx:19-21).

Do not drop a bare <FieldChip> with a long field name into a table-fixed column and expect it to wrap. FieldChip is inline-flex, so a bare string child cannot shrink below its longest word and paints over the next column; wrap it (WrappingFieldChip, wrapping-field-chip.tsx:11-17).

Before you adopt this#

Five questions to answer before reaching for FieldChip.

  1. Does the shell, a parent layout, or a global provider already render this? Not applicable, FieldChip is inline content; no shell already renders it.
  2. Does this app already ship a local implementation of the same thing? FileChip/WrappingFieldChip are the shipped app-local wrappers; extend one before adding props.
  3. Does this app's kit pin reach the version this component or prop landed in? Not applicable, no version-landed FieldChip prop is noted in this doc.
  4. Does the component derive its own accessible name and keyboard path, or must the call site supply them? Not applicable, FieldChip has no keyboard path; onClick alone makes it a button.
  5. Which canon §A rules bind this surface, and which does the composition break? §A1 says the three small-tag species are never interchangeable.

Travels with#

  • Table, as the field-name cell in a schema/attribute row.
  • IconFor, for the leading/trailing glyphs the app-local FileChip adds.

Snippet#

// speedway/app/components/wrapping-field-chip.tsx
export function WrappingFieldChip({ children }: { children: ReactNode }) {
return (
<FieldChip className="min-w-0">
<span className="min-w-0 break-words">{children}</span>
</FieldChip>
);
}
@versable-git/ui · reference, canon, and method, read in place