Editable
A component that allows users to edit text in place.
Anatomy
To set up the editable correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-partattribute to help identify them in the DOM.
Examples
Learn how to use the Editable component in your project. Let's take a look at the most basic example:
import { Editable } from '@ark-ui/react/editable'
export const Basic = () => (
<Editable.Root placeholder="Placeholder">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.Root>
)
import { Editable } from '@ark-ui/solid/editable'
export const Basic = () => (
<Editable.Root placeholder="Placeholder">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.Root>
)
<script setup lang="ts">
import { Editable } from '@ark-ui/vue/editable'
</script>
<template>
<Editable.Root placeholder="Placeholder">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.Root>
</template>
<script lang="ts">
import { Editable } from '@ark-ui/svelte/editable'
</script>
<Editable.Root placeholder="Placeholder">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.Root>
Custom 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.
import { Editable } from '@ark-ui/react/editable'
export const CustomControls = () => (
<Editable.Root placeholder="enter a value" defaultValue="Chakra">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
<Editable.Context>
{(editable) => (
<Editable.Control>
{editable.editing ? (
<>
<Editable.SubmitTrigger>Save</Editable.SubmitTrigger>
<Editable.CancelTrigger>Cancel</Editable.CancelTrigger>
</>
) : (
<Editable.EditTrigger>Edit</Editable.EditTrigger>
)}
</Editable.Control>
)}
</Editable.Context>
</Editable.Root>
)
import { Editable } from '@ark-ui/solid/editable'
import { Show } from 'solid-js'
export const CustomControls = () => (
<Editable.Root placeholder="enter a value" defaultValue="Chakra">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
<Editable.Context>
{(editable) => (
<Editable.Control>
<Show when={editable().editing} fallback={<Editable.EditTrigger>Edit</Editable.EditTrigger>}>
<Editable.SubmitTrigger>Save</Editable.SubmitTrigger>
<Editable.CancelTrigger>Canvel</Editable.CancelTrigger>
</Show>
</Editable.Control>
)}
</Editable.Context>
</Editable.Root>
)
<script setup lang="ts">
import { Editable } from '@ark-ui/vue/editable'
import { ref } from 'vue'
const value = ref('Chakra')
</script>
<template>
<Editable.Root placeholder="enter a value" v-model="value">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
<Editable.Context v-slot="{ editing }">
<Editable.Control v-if="editing">
<Editable.SubmitTrigger>Save</Editable.SubmitTrigger>
<Editable.CancelTrigger>Cancel</Editable.CancelTrigger>
</Editable.Control>
<Editable.Control v-else>
<Editable.EditTrigger>Edit</Editable.EditTrigger>
</Editable.Control>
</Editable.Context>
</Editable.Root>
</template>
<script lang="ts">
import { Editable } from '@ark-ui/svelte/editable'
</script>
<Editable.Root placeholder="Placeholder" defaultValue="Chakra">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
<Editable.Context>
{#snippet render(editable)}
<Editable.Control>
{#if editable().editing}
<Editable.SubmitTrigger>Save</Editable.SubmitTrigger>
<Editable.CancelTrigger>Cancel</Editable.CancelTrigger>
{:else}
<Editable.EditTrigger>Edit</Editable.EditTrigger>
{/if}
</Editable.Control>
{/snippet}
</Editable.Context>
</Editable.Root>
Auto-resizing
To auto-grow the editable as the content changes, set the autoResize prop to true.
<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.
<Editable.Root placeholder="Placeholder" autoResize maxLength={10}>
{/*...*/}
</Editable.Root>
Double click activation
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".
<Editable.Root placeholder="Placeholder" activationMode="dblclick">
{/*...*/}
</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.
import { Editable } from '@ark-ui/react/editable'
import { Field } from '@ark-ui/react/field'
export const WithField = (props: Field.RootProps) => (
<Field.Root {...props}>
<Editable.Root placeholder="Placeholder" activationMode="dblclick">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
import { Editable } from '@ark-ui/solid/editable'
import { Field } from '@ark-ui/solid/field'
export const WithField = (props: Field.RootProps) => (
<Field.Root {...props} readOnly>
<Editable.Root placeholder="Placeholder" activationMode="dblclick">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
)
<script setup lang="ts">
import { Editable } from '@ark-ui/vue/editable'
import { Field, type FieldRootProps } from '@ark-ui/vue/field'
const props = defineProps<FieldRootProps>()
</script>
<template>
<Field.Root v-bind="props">
<Editable.Root placeholder="Placeholder" activationMode="dblclick">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
</template>
<script lang="ts">
import { Editable } from '@ark-ui/svelte/editable'
import { Field } from '@ark-ui/svelte/field'
</script>
<Field.Root>
<Editable.Root placeholder="Placeholder">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.Root>
<Field.HelperText>Additional Info</Field.HelperText>
<Field.ErrorText>Error Info</Field.ErrorText>
</Field.Root>
Root Provider
Use the useEditable hook to create the editable store and pass it to the Editable.RootProvider component. This
allows you to have maximum control over the editable programmatically.
import { Editable, useEditable } from '@ark-ui/react/editable'
export const RootProvider = () => {
const editable = useEditable({ placeholder: 'Placeholder' })
return (
<>
<button onClick={() => editable.edit()}>Edit</button>
<Editable.RootProvider value={editable}>
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.RootProvider>
</>
)
}
import { Editable, useEditable } from '@ark-ui/solid/editable'
export const RootProvider = () => {
const editable = useEditable({ placeholder: 'Placeholder' })
return (
<>
<button onClick={() => editable().edit()}>Edit</button>
<Editable.RootProvider value={editable}>
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.RootProvider>
</>
)
}
<script setup lang="ts">
import { Editable, useEditable } from '@ark-ui/vue/editable'
const editable = useEditable({ placeholder: 'Placeholder' })
</script>
<template>
<button @click="editable.edit()">Edit</button>
<Editable.RootProvider :value="editable">
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.RootProvider>
</template>
<script lang="ts">
import { Editable, useEditable } from '@ark-ui/svelte/editable'
const editable = useEditable({ placeholder: 'Placeholder' })
</script>
<button onclick={() => editable().edit()}>Edit</button>
<Editable.RootProvider value={editable}>
<Editable.Label>Label</Editable.Label>
<Editable.Area>
<Editable.Input />
<Editable.Preview />
</Editable.Area>
</Editable.RootProvider>
If you're using the
Editable.RootProvidercomponent, you don't need to use theEditable.Rootcomponent.
API Reference
Root
| Prop | Default | Type |
|---|---|---|
activationMode | 'focus' | ActivationModeThe 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 | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
autoResize | booleanWhether the editable should auto-resize to fit the content. | |
defaultEdit | booleanWhether the editable is in edit mode by default. | |
defaultValue | stringThe initial value of the editable when rendered. Use when you don't need to control the value of the editable. | |
disabled | booleanWhether the editable is disabled. | |
edit | booleanWhether the editable is in edit mode. | |
finalFocusEl | () => HTMLElement | nullThe element to receive focus when the editable is closed. | |
form | stringThe associate form of the underlying input. | |
id | stringThe 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
}>The ids of the elements in the editable. Useful for composition. | |
invalid | booleanWhether the input's value is invalid. | |
maxLength | numberThe maximum number of characters allowed in the editable | |
name | stringThe name attribute of the editable component. Used for form submission. | |
onEditChange | (details: EditChangeDetails) => voidFunction to call when the edit mode changes. | |
onFocusOutside | (event: FocusOutsideEvent) => voidFunction called when the focus is moved outside the component | |
onInteractOutside | (event: InteractOutsideEvent) => voidFunction called when an interaction happens outside the component | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => voidFunction called when the pointer is pressed down outside the component | |
onValueChange | (details: ValueChangeDetails) => voidFunction to call when the value changes. | |
onValueCommit | (details: ValueChangeDetails) => voidFunction to call when the value is committed. | |
onValueRevert | (details: ValueChangeDetails) => voidFunction to call when the value is reverted. | |
placeholder | string | { edit: string; preview: string }The placeholder text for the editable. | |
readOnly | booleanWhether the editable is read-only. | |
required | booleanWhether the editable is required. | |
selectOnFocus | true | booleanWhether to select the text in the input when it is focused. |
submitMode | 'both' | SubmitModeThe 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 | IntlTranslationsThe translations for the editable. | |
value | stringThe controlled value of the editable. |
Area
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data 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
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Control
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
EditTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Input
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data 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
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data Attribute | Value |
|---|---|
[data-scope] | editable |
[data-part] | label |
[data-focus] | Present when focused |
[data-invalid] | Present when invalid |
Preview
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
| Data 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
| Prop | Default | Type |
|---|---|---|
value | UseEditableReturn | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
SubmitTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Accessibility
Keyboard Support
| Key | Description |
|---|---|
Enter | Saves the edited content and exits edit mode. |
Escape | Discards the changes and exits edit mode. |