# Editable

URL: https://ark-ui.com/docs/components/editable
Source: https://raw.githubusercontent.com/chakra-ui/ark/refs/heads/main/website/src/content/pages/components/editable.mdx

A component that allows users to edit text in place.

---

<ComponentPreview id="Editable" />

## Anatomy

<Anatomy id="editable" />

```tsx
<Editable.Root>
  <Editable.Label />
  <Editable.Area>
    <Editable.Input />
    <Editable.Preview />
  </Editable.Area>
  <Editable.Control>
    <Editable.EditTrigger />
    <Editable.SubmitTrigger />
    <Editable.CancelTrigger />
  </Editable.Control>
</Editable.Root>
```

## Examples

**Example: basic**

```ripple
import { Editable } from 'ark-ripple/editable';
import { Pencil } from 'lucide-ripple';
import styles from 'styles/editable.module.css';

export component Basic() {
  <Editable.Root class={styles.Root} placeholder="Enter text..." defaultValue="Hello World">
    <Editable.Label class={styles.Label}>{'Label'}</Editable.Label>
    <Editable.Area class={styles.Area}>
      <Editable.Input class={styles.Input} />
      <Editable.Preview class={styles.Preview} />
    </Editable.Area>
    <Editable.Control class={styles.Control}>
      <Editable.EditTrigger class={styles.EditTrigger}>
        <Pencil />
      </Editable.EditTrigger>
    </Editable.Control>
  </Editable.Root>
}

```

### Controlled

Use the `value` and `onValueChange` props to control the editable state.

**Example: controlled**

```ripple
import { Editable } from 'ark-ripple/editable';
import { Pencil } from 'lucide-ripple';
import { track } from 'ripple';
import styles from 'styles/editable.module.css';

export component Controlled() {
  let value = track('Hello World');

  <Editable.Root
    class={styles.Root}
    placeholder="Enter text..."
    {value}
    onValueChange={(e) => {
      @value = e.value;
    }}
  >
    <Editable.Label class={styles.Label}>{'Label'}</Editable.Label>
    <Editable.Area class={styles.Area}>
      <Editable.Input class={styles.Input} />
      <Editable.Preview class={styles.Preview} />
    </Editable.Area>
    <Editable.Control class={styles.Control}>
      <Editable.EditTrigger class={styles.EditTrigger}>
        <Pencil />
      </Editable.EditTrigger>
    </Editable.Control>
  </Editable.Root>
}

```

### Root Provider

An alternative way to control the editable is to use the `RootProvider` component and the `useEditable` hook. This way
you can access the state and methods from outside the component.

**Example: root-provider**

```ripple
import { Editable, useEditable } from 'ark-ripple/editable';
import { Pencil } from 'lucide-ripple';
import styles from 'styles/editable.module.css';

export component RootProvider() {
  const editable = useEditable({ defaultValue: 'Hello World' });

  <Editable.RootProvider class={styles.Root} value={editable}>
    <Editable.Label class={styles.Label}>{'Label'}</Editable.Label>
    <Editable.Area class={styles.Area}>
      <Editable.Input class={styles.Input} />
      <Editable.Preview class={styles.Preview} />
    </Editable.Area>
    <Editable.Control class={styles.Control}>
      <Editable.EditTrigger class={styles.EditTrigger}>
        <Pencil />
      </Editable.EditTrigger>
    </Editable.Control>
  </Editable.RootProvider>
}

```

### Context

Access the editable's state with `Editable.Context` or the `useEditableContext` hook—great for showing keyboard hints
when editing.

**Example: context**

```ripple
import { Editable } from 'ark-ripple/editable';
import { Pencil } from 'lucide-ripple';
import styles from 'styles/editable.module.css';

export component Context() {
  <Editable.Root class={styles.Root} placeholder="Enter text..." defaultValue="Hello World">
    <Editable.Label class={styles.Label}>{'Label'}</Editable.Label>
    <Editable.Area class={styles.Area}>
      <Editable.Input class={styles.Input} />
      <Editable.Preview class={styles.Preview} />
    </Editable.Area>
    <Editable.Context>
      component children({ context }) {
        if (@context.editing) {
          <span class={styles.HelperText}>{'Enter to save, Esc to cancel'}</span>
        } else {
          <Editable.Control class={styles.Control}>
            <Editable.EditTrigger class={styles.EditTrigger}>
              <Pencil />
            </Editable.EditTrigger>
          </Editable.Control>
        }
      }
    </Editable.Context>
  </Editable.Root>
}

```

### Controls

In some cases, you might need to use custom controls to toggle the edit and read mode. We use the render prop pattern to
provide access to the internal state of the component.

**Example: controls**

```ripple
import { Editable } from 'ark-ripple/editable';
import { Check, Pencil, X } from 'lucide-ripple';
import styles from 'styles/editable.module.css';

export component Controls() {
  <Editable.Root class={styles.Root} defaultValue="Click edit to start">
    <Editable.Label class={styles.Label}>{'Label'}</Editable.Label>
    <Editable.Area class={styles.Area}>
      <Editable.Input class={styles.Input} />
      <Editable.Preview class={styles.Preview} />
    </Editable.Area>
    <Editable.Context>
      component children({ context }) {
        <Editable.Control class={styles.Control}>
          if (@context.editing) {
            <Editable.SubmitTrigger class={styles.SubmitTrigger}>
              <Check />
            </Editable.SubmitTrigger>
            <Editable.CancelTrigger class={styles.CancelTrigger}>
              <X />
            </Editable.CancelTrigger>
          } else {
            <Editable.EditTrigger class={styles.EditTrigger}>
              <Pencil />
            </Editable.EditTrigger>
          }
        </Editable.Control>
      }
    </Editable.Context>
  </Editable.Root>
}

```

### Textarea

Use the `asChild` prop on `Editable.Input` to render a textarea for multi-line editing.

**Example: textarea**

```ripple
import { Editable } from 'ark-ripple/editable';
import styles from 'styles/editable.module.css';

export component WithTextarea() {
  <Editable.Root
    class={styles.Root}
    placeholder="Enter a description..."
    defaultValue="Ark UI is a headless component library for building reusable, scalable design systems."
    activationMode="dblclick"
  >
    <Editable.Label class={styles.Label}>{'Description'}</Editable.Label>
    <Editable.Area class={styles.Area}>
      <Editable.Input class={styles.Input}>
        component asChild({ propsFn }) {
          <textarea {...propsFn()} />
        }
      </Editable.Input>
      <Editable.Preview class={styles.Preview} />
    </Editable.Area>
    <div class={styles.HelperText}>{'Press Cmd + Enter to save'}</div>
  </Editable.Root>
}

```

### Field

The `Field` component helps manage form-related state and accessibility attributes of an editable. It includes handling
ARIA labels, helper text, and error text to ensure proper accessibility.

**Example: with-field**

```ripple
import { Editable } from 'ark-ripple/editable';
import { Field } from 'ark-ripple/field';
import field from 'styles/field.module.css';
import styles from 'styles/editable.module.css';

export component WithField() {
  <Field.Root class={field.Root}>
    <Editable.Root class={styles.Root} placeholder="Enter your bio">
      <Editable.Label class={field.Label}>{'Bio'}</Editable.Label>
      <Editable.Area class={styles.Area}>
        <Editable.Input class={styles.Input} />
        <Editable.Preview class={styles.Preview} />
      </Editable.Area>
    </Editable.Root>
    <Field.HelperText class={field.HelperText}>{'Click to edit your bio'}</Field.HelperText>
    <Field.ErrorText class={field.ErrorText}>{'Bio is required'}</Field.ErrorText>
  </Field.Root>
}

```

## Guides

### Auto-resizing

To auto-grow the editable as the content changes, set the `autoResize` prop to `true`.

```tsx
<Editable.Root placeholder="Placeholder" autoResize>
  {/*...*/}
</Editable.Root>
```

### Max Length

Use the `maxLength` prop to set a maximum number of characters that can be entered into the editable.

```tsx
<Editable.Root placeholder="Placeholder" autoResize maxLength={10}>
  {/*...*/}
</Editable.Root>
```

### Double Click

The editable supports two modes of activating the "edit" state:

- when the preview part is focused (with pointer or keyboard).
- when the preview part is double-clicked.

To change the mode to double-click, pass the prop `activationMode="dblclick"`.

```tsx
<Editable.Root placeholder="Placeholder" activationMode="dblclick">
  {/*...*/}
</Editable.Root>
```

## API Reference

### Props

**Component API Reference**

**Root Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `activationMode` | `ActivationMode` | No | The activation mode for the preview element.

- "focus" - Enter edit mode when the preview is focused
- "dblclick" - Enter edit mode when the preview is double-clicked
- "click" - Enter edit mode when the preview is clicked
- "none" - Edit can be triggered programmatically only |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |
| `autoResize` | `boolean` | No | Whether the editable should auto-resize to fit the content. |
| `defaultEdit` | `boolean` | No | Whether the editable is in edit mode by default. |
| `defaultValue` | `string` | No | The initial value of the editable when rendered.
Use when you don't need to control the value of the editable. |
| `disabled` | `boolean` | No | Whether the editable is disabled. |
| `edit` | `boolean` | No | Whether the editable is in edit mode. |
| `finalFocusEl` | `() => HTMLElement | null` | No | The element to receive focus when the editable is closed. |
| `form` | `string` | No | The associate form of the underlying input. |
| `id` | `string` | No | The unique identifier of the machine. |
| `ids` | `Partial<{
  root: string
  area: string
  label: string
  preview: string
  input: string
  control: string
  submitTrigger: string
  cancelTrigger: string
  editTrigger: string
}>` | No | The ids of the elements in the editable. Useful for composition. |
| `invalid` | `boolean` | No | Whether the input's value is invalid. |
| `maxLength` | `number` | No | The maximum number of characters allowed in the editable |
| `name` | `string` | No | The name attribute of the editable component. Used for form submission. |
| `onEditChange` | `(details: EditChangeDetails) => void` | No | Function to call when the edit mode changes. |
| `onFocusOutside` | `(event: FocusOutsideEvent) => void` | No | Function called when the focus is moved outside the component |
| `onInteractOutside` | `(event: InteractOutsideEvent) => void` | No | Function called when an interaction happens outside the component |
| `onPointerDownOutside` | `(event: PointerDownOutsideEvent) => void` | No | Function called when the pointer is pressed down outside the component |
| `onValueChange` | `(details: ValueChangeDetails) => void` | No | Function to call when the value changes. |
| `onValueCommit` | `(details: ValueChangeDetails) => void` | No | Function to call when the value is committed. |
| `onValueRevert` | `(details: ValueChangeDetails) => void` | No | Function to call when the value is reverted. |
| `placeholder` | `string | { edit: string; preview: string }` | No | The placeholder text for the editable. |
| `readOnly` | `boolean` | No | Whether the editable is read-only. |
| `required` | `boolean` | No | Whether the editable is required. |
| `selectOnFocus` | `boolean` | No | Whether to select the text in the input when it is focused. |
| `submitMode` | `SubmitMode` | No | The action that triggers submit in the edit mode:

- "enter" - Trigger submit when the enter key is pressed
- "blur" - Trigger submit when the editable is blurred
- "none" - No action will trigger submit. You need to use the submit button
- "both" - Pressing `Enter` and blurring the input will trigger submit |
| `translations` | `IntlTranslations` | No | The translations for the editable. |
| `value` | `string` | No | The controlled value of the editable. |


**Area Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Area Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | editable |
| `[data-part]` | area |
| `[data-focus]` | Present when focused |
| `[data-disabled]` | Present when disabled |
| `[data-placeholder-shown]` | Present when placeholder is shown |


**CancelTrigger Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Control Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**EditTrigger Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Input Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Input Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | editable |
| `[data-part]` | input |
| `[data-disabled]` | Present when disabled |
| `[data-readonly]` | Present when read-only |
| `[data-invalid]` | Present when invalid |
| `[data-autoresize]` |  |


**Label Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Label Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | editable |
| `[data-part]` | label |
| `[data-focus]` | Present when focused |
| `[data-invalid]` | Present when invalid |
| `[data-required]` | Present when required |


**Preview Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**Preview Data Attributes:**

| Attribute | Value |
|-----------|-------|
| `[data-scope]` | editable |
| `[data-part]` | preview |
| `[data-placeholder-shown]` | Present when placeholder is shown |
| `[data-readonly]` | Present when read-only |
| `[data-disabled]` | Present when disabled |
| `[data-invalid]` | Present when invalid |
| `[data-autoresize]` |  |


**RootProvider Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `value` | `UseEditableReturn` | Yes |  |
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


**SubmitTrigger Props:**

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `asChild` | `boolean` | No | Use the provided child element as the default rendered element, combining their props and behavior. |


### Context

**API:**

| Property | Type | Description |
|----------|------|-------------|
| `editing` | `boolean` | Whether the editable is in edit mode |
| `empty` | `boolean` | Whether the editable value is empty |
| `value` | `string` | The current value of the editable |
| `valueText` | `string` | The current value of the editable, or the placeholder if the value is empty |
| `setValue` | `(value: string) => void` | Function to set the value of the editable |
| `clearValue` | `VoidFunction` | Function to clear the value of the editable |
| `edit` | `VoidFunction` | Function to enter edit mode |
| `cancel` | `VoidFunction` | Function to exit edit mode, and discard any changes |
| `submit` | `VoidFunction` | Function to exit edit mode, and submit any changes |


## Accessibility

### Keyboard Support

<KeyBindingsTable id="editable" />