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-part
attribute 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>
Using 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" value="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>
Auto-resizing the editable
To auto-grow the editable as the content changes, set the autoResize
prop to true
.
<Editable.Root placeholder="Placeholder" autoResize>
{/*...*/}
</Editable.Root>
Setting a maxWidth
It is a common pattern to set a maximum of the editable as it auto-grows. To achieve this, set the
maxWidth
prop to the desired value.
<Editable.Root placeholder="Placeholder" autoResize maxWidth="320px">
{/*...*/}
</Editable.Root>
Editing with 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"
.
<Editable.Root placeholder="Placeholder" activationMode="dblclick">
{/*...*/}
</Editable.Root>
Using the Field Component
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 } from '@ark-ui/vue/field'
</script>
<template>
<Field.Root>
<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>
Using the Root Provider
The RootProvider
component provides a context for the editable. It accepts the value of the useEditable
hook.
You can leverage it to access the component state and methods from outside the editable.
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>
If you're using the
RootProvider
component, you don't need to use theRoot
component.
API Reference
Root
Prop | Default | Type |
---|---|---|
activationMode | 'focus' | ActivationMode 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 |
asChild | (props: ParentProps<'div'>) => Element Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
autoResize | boolean Whether the editable should auto-resize to fit the content. | |
defaultEdit | boolean The initial edit state of the editable when it is first rendered. Use when you do not need to control its edit state. | |
defaultValue | string The initial value of the editable when it is first rendered. Use when you do not need to control the state of the editable. | |
disabled | boolean Whether the editable is disabled | |
edit | boolean Whether the editable is in edit mode. | |
finalFocusEl | () => HTMLElement | null The element that should receive focus when the editable is closed. By default, it will focus on the trigger element. | |
form | string The associate form of the underlying input. | |
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 | boolean Whether the input's value is invalid. | |
maxLength | number The maximum number of characters allowed in the editable | |
name | string The name attribute of the editable component. Used for form submission. | |
onEditChange | (details: EditChangeDetails) => void The callback that is called when the edit mode is changed | |
onFocusOutside | (event: FocusOutsideEvent) => void Function called when the focus is moved outside the component | |
onInteractOutside | (event: InteractOutsideEvent) => void Function called when an interaction happens outside the component | |
onPointerDownOutside | (event: PointerDownOutsideEvent) => void Function called when the pointer is pressed down outside the component | |
onValueChange | (details: ValueChangeDetails) => void The callback that is called when the editable's value is changed | |
onValueCommit | (details: ValueChangeDetails) => void The callback that is called when the editable's value is submitted. | |
onValueRevert | (details: ValueChangeDetails) => void The callback that is called when the esc key is pressed or the cancel button is clicked | |
placeholder | string | { edit: string; preview: string } The placeholder value to show when the `value` is empty | |
readOnly | boolean Whether the editable is readonly | |
required | boolean Whether the editable is required | |
selectOnFocus | true | boolean Whether to select the text in the input when it is focused. |
submitMode | 'both' | SubmitMode 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 Specifies the localized strings that identifies the accessibility elements and their states | |
value | string The value of the editable in both edit and preview mode |
Area
Prop | Default | Type |
---|---|---|
asChild | (props: ParentProps<'div'>) => Element Use 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 | (props: ParentProps<'button'>) => Element Use 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 | (props: ParentProps<'div'>) => Element Use 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 | (props: ParentProps<'button'>) => Element Use 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 | (props: ParentProps<'input'>) => Element Use 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 | (props: ParentProps<'label'>) => Element Use 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 | (props: ParentProps<'span'>) => Element Use 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 | (props: ParentProps<'div'>) => Element Use 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 | (props: ParentProps<'button'>) => Element Use 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. |