KeyValueEditor
A small table of names and values, like environment variables or headers.
SourcePackage @weft-js/warp
Preview
tsx
import { state } from '@weft-js/core'import { KeyValueEditor, Stack, Text } from '@weft-js/warp'export function Env() { const env = state(ENV) return ( <Stack gap="related"> <KeyValueEditor label="Environment variables" keyLabel="Name" value={env} /> <Text subtle>{env.value.filter(r => r.key).length} variables reach the next deploy.</Text> </Stack> )}const ENV = [{ key: 'NODE_ENV', value: 'production' }, { key: 'API_URL', value: 'https://api.weft.dev' }, { key: 'LOG_LEVEL', value: 'info' }]Installation
npm install @weft-js/warpUsage
tsx
import { KeyValueEditor } from '@weft-js/warp'Form or JSON
json adds a switch. Both views edit the same value.
tsx
import { KeyValueEditor } from '@weft-js/warp'export function Json() { return ( <KeyValueEditor label="Response headers" keyLabel="Header" json defaultValue={HEADERS} /> )}const HEADERS = [{ key: 'Cache-Control', value: 'max-age=30' }, { key: 'X-Frame-Options', value: 'DENY' }]A repeated key
A warning, not a block: the last one wins.
tsx
import { KeyValueEditor } from '@weft-js/warp'export function Duplicate() { return ( <KeyValueEditor label="Environment variables" keyLabel="Name" defaultValue={[...ENV, { key: 'LOG_LEVEL', value: 'debug' }]} /> )}const ENV = [{ key: 'NODE_ENV', value: 'production' }, { key: 'API_URL', value: 'https://api.weft.dev' }, { key: 'LOG_LEVEL', value: 'info' }]States
A key value editor can start empty or filled, and can show a hint or an error.
tsx
import { Grid, KeyValueEditor, Stack, Text } from '@weft-js/warp'export function States() { return ( <Grid cols={2} gap="group"> <Cell name="Empty"><KeyValueEditor label="Response headers" /></Cell> <Cell name="Filled"><KeyValueEditor label="Response headers" defaultValue={HEADERS} /></Cell> <Cell name="Hint"><KeyValueEditor label="Response headers" hint="Added to every response." defaultValue={HEADERS} /></Cell> <Cell name="Invalid"><KeyValueEditor label="Response headers" error="X-Frame-Options can't be changed on this plan." defaultValue={HEADERS} /></Cell> </Grid> )}const Cell = (p: { name: string; children?: unknown }) => ( <Stack gap="tight"> <Text role="caption" subtle>{p.name}</Text> {p.children} </Stack>)const HEADERS = [{ key: 'Cache-Control', value: 'max-age=30' }, { key: 'X-Frame-Options', value: 'DENY' }]When to use
Use it for
- Pairs people add and remove by hand
Reach for something else
- JsonEditor, when values nest
Accessibility
- Tab
- Moves from cell to cell
- Enter
- On Add row, adds one and moves to it
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | The visible name, and what screen readers announce. |
hint | unknown | — | A short line of help under the field. |
error | unknown | — | Replaces the hint and marks the field invalid. |
icon | IconRef | — | Leading icon: it sweeps with the border. |
prefix | unknown | — | Text or an element inside the field before the value, such as $. |
suffix | unknown | — | Text or an element inside the field after the value, such as kg. |
variant | "floating" | "classic" | — | floating (default, or the app's warp({ fields })) · classic: the label above. |
appearance | "line" | — | line: only a bottom line under the value, no box or fill. The boxed field otherwise. |
size | "sm" | "md" | "lg" | 'md' | Control size. md by default. |
clearable | boolean | false | A clear button (shown once there is a value). |
counter | number | — | Maximum length, shown as a counter. |
id | string | — | The element id. One is made for you if you leave it out. |
disabled | boolean | false | Can't be focused or changed. |
readonly | boolean | false | Shows the value and lets it be selected and copied, but not changed. |
value | KeyValue[] | State<KeyValue[]> | — | The rows as { key, value }, or a State to bind. |
defaultValue | KeyValue[] | — | The starting value, when the component owns the state. |
keyLabel | string | 'Key' | The first column's heading. |
valueLabel | string | 'Value' | The second column's heading. |
json | boolean | false | Adds a switch to a JSON view of the same value. |
| Event | Type | Default | Description |
|---|---|---|---|
onInput | ((e: InputEvent & { currentTarget: HTMLInputElement & HTMLTextAreaElemen… | — | Called on each keystroke. |
onValueChange | ((v: KeyValue[], reason: ChangeReason) => void) | — | Hears the new rows and why they changed. |
Parts
Every element carries a stable name, so you can style it from your own CSS: [data-scope="kv"] [data-part="remove"]
removeaddsr-only
RelatedJson editorTable