Redpanda UI
RC
Redpanda UI

Key Value Pattern

Composing editable key-value forms and displaying them in readonly mode as badges.

Made by eblairmckee

Key-value pairs are common in resource management UIs — labels, tags, environment variables, HTTP headers. This pattern covers how to compose the editable form and how to present the data in readonly contexts.

Loading component...

Editable Mode

Use KeyValueField for the editable form. It handles dynamic row management, duplicate key detection, and focus management out of the box.

Loading component...

With Predefined Options

When keys or values come from a known set, use mode: 'combobox' with creatable: true to let users pick from suggestions or type custom values.

Loading component...

With Validation

Use keyValuePairsSchema from input-utils with React Hook Form + Zod to validate key-value pairs on form submission. The schema checks for duplicate keys, empty keys, character patterns, and length limits.

Loading component...

Readonly Mode

When displaying key-value data outside a form — in detail views, tables, or summaries — render them as badges inside a BadgeGroup. Use maxVisible to cap the visible count and show the rest in an overflow tooltip.

import { Badge } from "@/components/redpanda-ui/badge"
import { BadgeGroup } from "@/components/redpanda-ui/badge-group"
import { List, ListItem } from "@/components/redpanda-ui/typography"

const tags = [
  { key: "environment", value: "production" },
  { key: "region", value: "us-east-1" },
];

<BadgeGroup
  maxVisible={3}
  renderOverflowContent={(overflow) => (
    <List>
      {tags.slice(-overflow.length).map((tag) => (
        <ListItem key={tag.key}>
          {tag.key}: {tag.value}
        </ListItem>
      ))}
    </List>
  )}
  variant="simple-outline"
>
  {tags.map((tag) => (
    <Badge key={tag.key} variant="simple-outline">
      {tag.key}: {tag.value}
    </Badge>
  ))}
</BadgeGroup>

Anatomy

Editable mode
┌─────────────────────────────────────┐
│ KeyValueField                       │
│ ├── Label + Description             │
│ ├── Row [Key input] [Value input] ✕ │
│ ├── Row [Key input] [Value input] ✕ │
│ └── [+ Add] button                  │
└─────────────────────────────────────┘

Readonly mode
┌─────────────────────────────────────┐
│ Label                               │
│ BadgeGroup                          │
│ ├── Badge "env: production"         │
│ ├── Badge "region: us-east-1"       │
│ └── +2 more (overflow tooltip)      │
└─────────────────────────────────────┘

Best Practices

  1. Limit visible badges — Use maxVisible on BadgeGroup to keep layouts compact. 3–5 is a good default depending on available space.
  2. Use simple-outline variant — Keeps badges visually lightweight for metadata display. Reserve colored variants for status indicators.
  3. Filter empty keys — Before rendering readonly badges, filter out pairs with empty keys so incomplete entries don't leak into the display.
  4. Cap items in forms — Use the maxItems prop on KeyValueField to prevent unbounded growth. Common limits are 10–50 depending on the resource type.
  5. Validate before submission — Use validateKeyValuePairs to catch duplicates and empty keys before the form is submitted, not just on blur.
  6. Show the diff on save — When editing existing tags, use getKeyValueDiff to show users what will change before they confirm.

Built by malinskibeniamin. The source code is available on GitHub.

On this page