---
url: /en/docs/fields/keyvalue.md
description: >-
  Create and manage dynamic key-value pairs in Sveltia CMS for flexible data
  structures.
---

# KeyValue Field

The KeyValue field type allows users to create and manage a dynamic list of key-value pairs, or dictionary entries, within the CMS entry form.

## User Interface

### Editor

A dynamic list of key-value pairs, where users can add, edit, reorder and remove entries. Each entry consists of a text input for the key and a text input for the value.

* Pressing Enter moves focus or adds a new row while editing.
* Each pair can be reordered using the drag handle at the start of its row, with the same pointer, keyboard and touch screen behavior as the [List field](/en/docs/fields/list#complex-list-field). The pairs are saved in the order they are shown.
* A field without pairs shows a blank row, like a [simple List field](/en/docs/fields/list#simple-list-field), so there’s always somewhere to type. The blank row isn’t saved until its key is filled in, and removing the last pair leaves one in its place.

### Preview

A table displaying the current key-value pairs in a structured format for easy review.

## Data Type

An object where each key corresponds to a user-defined key and each value corresponds to the associated value.

If the `required` option is set to `false` and the field is left empty, the value will be an empty object.

## Data Validation

* If the `required` option is set to `true`, at least one key-value pair must be present. A blank pair, with neither a key nor a value, doesn’t count.
* Keys must be unique and non-empty strings. Keys cannot contain dots (`.`) as they may interfere with nested data structures.
* If `min` and/or `max` options are specified, the number of key-value pairs must be within the defined limits.

## Options

In addition to the [common field options](/en/docs/fields#common-options), the KeyValue field supports the following options:

### Required Options

#### `widget`

* **Type**: `string`
* **Default**: `string`

Must be set to `keyvalue`.

### Optional Options

#### `default`

* **Type**: `object`
* **Default**: `{}`

The default value for the field when creating a new entry.

#### `key_label`

* **Type**: `string`
* **Default**: `"Key"` or its localized equivalent

The label for the key input field.

#### `value_label`

* **Type**: `string`
* **Default**: `"Value"` or its localized equivalent

The label for the value input field.

#### `label_singular`

* **Type**: `string`
* **Default**: The value of the `label` option

A label used for a single key-value pair, e.g., “Setting” for a field labeled “Settings”. It will be displayed on the Add button, just like the [`label_singular` option for the List field](/en/docs/fields/list#label-singular).

#### `min`

* **Type**: `integer`
* **Default**: `0`

The minimum number of key-value pairs required. This enables validation to ensure that users add at least this many entries.

#### `max`

* **Type**: `integer`
* **Default**: `Infinity`

The maximum number of key-value pairs allowed. This enables validation to prevent users from adding more than this many entries.

#### `root`

* **Type**: `boolean`
* **Default**: `false`

If set to `true`, the key-value pairs will be stored at the root level of the entry data instead of nested under the field name. This is similar to how the [`root` option for the List field](/en/docs/fields/list#root) works. The option is ignored unless the field is the only field in the collection or file.

See the [Top-Level key-value pairs](#top-level-key-value-pairs) example below for details.

#### `i18n`

* **Type**: `boolean`, `duplicate` or `duplicate_keys`
* **Default**: `false`

In addition to the [common `i18n` option values](/en/docs/i18n/options#field-level-configuration), the KeyValue field accepts the `duplicate_keys` value, which is useful for dictionaries whose keys are shared across locales while their values are translated:

* The keys are copied from the default locale to the other locales, where they are read-only. Keys can only be added, renamed or removed in the default locale, and any such change is immediately reflected in the other locales.
* The values can be edited separately for each locale. When a key is renamed in the default locale, the other locales keep the value they had under the old name; a newly added key starts with an empty value in the other locales.
* The order of the keys follows the default locale as well: reordering the pairs there reorders them in the other locales, which keep their own values.

See the [Translated Values with Shared Keys](#translated-values-with-shared-keys) example below for details.

## Examples

### Basic Key-Value Field

This example demonstrates a simple KeyValue field configuration:

::: code-group

```yaml [YAML]
- name: settings
  label: Settings
  widget: keyvalue
```

```toml [TOML]
[[fields]]
name = "settings"
label = "Settings"
widget = "keyvalue"
```

```json [JSON]
{
  "name": "settings",
  "label": "Settings",
  "widget": "keyvalue"
}
```

```js [JavaScript]
{
  name: 'settings',
  label: 'Settings',
  widget: 'keyvalue',
}
```

:::

Output example:

::: code-group

```yaml [YAML]
settings:
  theme: dark
  notifications: enabled
```

```toml [TOML]
[settings]
theme = "dark"
notifications = "enabled"
```

```json [JSON]
{
  "settings": {
    "theme": "dark",
    "notifications": "enabled"
  }
}
```

:::

### Translated Values with Shared Keys

This example demonstrates how to use the `duplicate_keys` i18n strategy so that the same keys are used in all locales while the values are translated. This requires i18n to be [enabled](/en/docs/i18n) for the collection:

::: code-group

```yaml{4} [YAML]
- name: labels
  label: Labels
  widget: keyvalue
  i18n: duplicate_keys
```

```toml{5} [TOML]
[[fields]]
name = "labels"
label = "Labels"
widget = "keyvalue"
i18n = "duplicate_keys"
```

```json{5} [JSON]
{
  "name": "labels",
  "label": "Labels",
  "widget": "keyvalue",
  "i18n": "duplicate_keys"
}
```

```js{5} [JavaScript]
{
  name: 'labels',
  label: 'Labels',
  widget: 'keyvalue',
  i18n: 'duplicate_keys',
}
```

:::

Output example, with English as the default locale and the `single_file` i18n structure:

::: code-group

```yaml [YAML]
en:
  labels:
    submit: Submit
    cancel: Cancel
ja:
  labels:
    submit: 送信
    cancel: キャンセル
```

```toml [TOML]
[en.labels]
submit = "Submit"
cancel = "Cancel"

[ja.labels]
submit = "送信"
cancel = "キャンセル"
```

```json [JSON]
{
  "en": {
    "labels": {
      "submit": "Submit",
      "cancel": "Cancel"
    }
  },
  "ja": {
    "labels": {
      "submit": "送信",
      "cancel": "キャンセル"
    }
  }
}
```

:::

### Top-Level Key-Value Pairs

This example demonstrates how to use the `root` option to store key-value pairs at the root level of the entry data:

::: code-group

```yaml{4} [YAML]
- name: settings
  label: Settings
  widget: keyvalue
  root: true
```

```toml{5} [TOML]
[[fields]]
name = "settings"
label = "Settings"
widget = "keyvalue"
root = true
```

```json{5} [JSON]
{
  "name": "settings",
  "label": "Settings",
  "widget": "keyvalue",
  "root": true
}
```

```js{5} [JavaScript]
{
  name: 'settings',
  label: 'Settings',
  widget: 'keyvalue',
  root: true,
}
```

:::

Output example:

::: code-group

```yaml [YAML]
theme: dark
notifications: enabled
```

```toml [TOML]
theme = "dark"
notifications = "enabled"
```

```json [JSON]
{
  "theme": "dark",
  "notifications": "enabled"
}
```

:::
