Key Value
One or more muted-label / medium-value rows.
A list of label–value rows. The label is muted and the value is medium.
Set emphasis="key" to flip that: the label is medium and the value is
muted. Set emphasizeLabel and the label becomes medium, in the same
color as the value, without muting the value.
KeyValue is the wrapper — it owns density, separators, and an internal
Item List. Put KeyValueRow (or
KeyValueSkeleton) inside it. Do not nest KeyValue inside another Item
List.
Set onEdit on a row and an Edit link with a chevron sits under the value.
labelHelp sits under the label. valueHelp sits under the value. Rows do
not change on hover. density is condensed, default, or relaxed
(set on KeyValue, overridable per row). relaxed is the roomier row.
variant is divided (default — inner-border under each row except the last)
or borderless (no separators). Use borderless with condensed for
tight stacks. Set flush (or use a flushBody Split Card
panel) and the first row drops top padding and the last drops bottom padding
(or set flushTop / flushBottom yourself). Panel chrome padding is
unchanged.
Omit labelWidth and the label takes the leftover space, so the help
stays on one line when it fits. Set labelWidth (any CSS length) and the
value fills whatever is left. align is end by default; start lines
the value up on the left of its column.
You might be looking for:
- Item List
Free-form selectable rows — not a table.
- Table
Dense columnar data — styled table or Slick Data Table.
Usage
import { KeyValue, KeyValueRow, SectionCard } from "@sophic/portal-ui";
import { CardContent } from "@sophic/portal-ui/components/ui/card";
<SectionCard title="Profile" flushBody>
<CardContent className="px-0 py-0">
<KeyValue density="relaxed">
<KeyValueRow
label="Preferred name"
labelHelp="What we call you in emails, calls and the app."
emphasizeLabel
value="Alex"
editLabel="Edit preferred name"
onEdit={() => {}}
/>
<KeyValueRow
label="Legal name"
labelWidth="11rem"
align="start"
value="Alex Michael"
/>
</KeyValue>
</CardContent>
</SectionCard>;
{/* Tight stack — holding drawer */}
<KeyValue variant="borderless" density="condensed">
<KeyValueRow label="Market value" value="€170.04" />
</KeyValue>Put px-0 py-0 on CardContent so the rows reach both card edges. Prefer
variant over adding divide-y on a list.
Props
KeyValueProps
Prop
Type
Default
KeyValueRowProps
Prop
Type
Default
KeyValueSkeletonProps
Prop
Type
Default
Changelog
- 4 October 2026 —
flushcollapses first/last row padding without a Split Card. Activity drawers use it; referenced-object facts areborderless+condensed. Full notes - 30 September 2026 —
emphasis="key"makes the label medium and the value muted. Full notes - 29 September 2026 —
KeyValuewraps rows;KeyValueRowis one row. Full notes - 29 September 2026 —
variant:divided(default) orborderless.condensedpadding ispy-1.5.flushBodySplit Card panels collapse first-row top / last-row bottom Key Value padding (flushTop/flushBottomalso work). Full notes - 29 September 2026 —
KeyValueSkeletonpulses a label, help line, and value so loading rows match the loaded ones. Full notes - 29 September 2026 —
densitymatches Table:condensed,default, orrelaxed. Full notes - 29 September 2026 — Edit is a link with a chevron under the value. Rows do not react to hover. Full notes
- 28 September 2026 — Added for a muted label and a medium value. Full notes