{"slug":"editable","title":"Editable","description":"Using the editable machine in your project.","contentType":"component","framework":"react","content":"Editable is an input field used for editing a single line of text. It renders as\nstatic text and transforms into a text input field when then edit interaction is\ntriggered (click, focus, or double-click).\n\n## Resources\n\n\n[Latest version: v1.31.0](https://www.npmjs.com/package/@zag-js/editable)\n[Logic Visualizer](https://zag-visualizer.vercel.app/editable)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/editable)\n\n\n\n**Features**\n\n- Use custom controls for the editable\n- Pressing `Enter` commits the input value\n- Pressing `Esc` reverts the value\n- Activate edit mode by double-clicking or focusing on the preview text\n- Auto-resize input to fit content\n\n## Installation\n\nTo use the editable machine in your project, run the following command in your\ncommand line:\n\n```bash\nnpm install @zag-js/editable @zag-js/react\n# or\nyarn add @zag-js/editable @zag-js/react\n```\n\n## Anatomy\n\nTo set up the editable correctly, you'll need to understand its anatomy and how\nwe name its parts.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nFirst, import the editable package into your project\n\n```jsx\nimport * as editable from \"@zag-js/editable\"\n```\n\nThe editable package exports two key functions:\n\n- `machine` — The state machine logic for the editable widget.\n- `connect` — The function that translates the machine's state to JSX attributes\n  and event handlers.\n\n> You'll need to provide a unique `id` to the `useMachine` hook. This is used to\n> ensure that every part has a unique identifier.\n\nNext, import the required hooks and functions for your framework and use the\neditable machine in your project 🔥\n\n```jsx\nimport * as editable from \"@zag-js/editable\"\nimport { useMachine, normalizeProps } from \"@zag-js/react\"\n\nexport default function Editable() {\n  const service = useMachine(editable.machine, { id: \"1\" })\n\n  const api = editable.connect(service, normalizeProps)\n\n  return (\n    <div {...api.getRootProps()}>\n      <div {...api.getAreaProps()}>\n        <input {...api.getInputProps()} />\n        <span {...api.getPreviewProps()} />\n      </div>\n    </div>\n  )\n}\n```\n\n### Setting the initial value\n\nTo set the initial value of the editable, pass the `defaultValue` property to\nthe machine's context.\n\n```jsx {2}\nconst service = useMachine(editable.machine, {\n  defaultValue: \"Hello World\",\n})\n```\n\n### Listening for value changes\n\nThe editable machine supports two ways of listening for value changes:\n\n- `onValueChange`: called when value changes.\n- `onValueCommit`: called when the value is committed.\n\n```jsx {2-4}\nconst service = useMachine(editable.machine, {\n  onValueChange(details) {\n    console.log(\"Value changed\", details.value)\n  },\n  onValueCommit(details) {\n    console.log(\"Value submitted\", details.value)\n  },\n})\n```\n\n### Using custom controls\n\nIn some cases, you might need to use custom controls to toggle the edit and read\nmode. We use the render prop pattern to provide access to the internal state of\nthe component.\n\n```jsx\nimport * as editable from \"@zag-js/editable\"\nimport { useMachine } from \"@zag-js/react\"\n\nexport default function Editable() {\n  const service = useMachine(editable.machine, { id: \"1\" })\n\n  const api = editable.connect(service)\n\n  return (\n    <div {...api.getRootProps()}>\n      <div {...api.getAreaProps()}>\n        <input {...api.getInputProps()} />\n        <span {...api.getPreviewProps()} />\n      </div>\n      <div>\n        {!api.editing && <button {...api.getEditTriggerProps()}>Edit</button>}\n        {api.editing && (\n          <div>\n            <button {...api.getSubmitTriggerProps()}>Save</button>\n            <button {...api.getCancelTriggerProps()}>Cancel</button>\n          </div>\n        )}\n      </div>\n    </div>\n  )\n}\n```\n\n### Auto-resizing\n\nTo auto-grow the editable as the content changes, pass the `autoResize: true`\nproperty to the machine's context.\n\n```jsx {2}\nconst service = useMachine(editable.machine, {\n  autoResize: true,\n})\n```\n\nWhen using autoresize, the input and preview elements should not have any\nstyles. Use `all: unset` if needed and pass any styles to the \"area\" element\nsince its shared by the input and preview elements.\n\n### Setting a maxWidth\n\nIt is a common pattern to set a maximum of the editable as it auto-grows. To\nachieve this, set the `maxWidth` property of the machine's context to the\ndesired value.\n\n```jsx {2-3}\nconst service = useMachine(editable.machine, {\n  autoResize: true,\n  maxWidth: \"320px\",\n})\n```\n\nWhen the editable reaches the specified max-width, it'll clip the preview text\nwith an ellipsis.\n\n### Editing with double click\n\nThe editable supports two modes of activating the \"edit\" state:\n\n- when the preview part is focused (with pointer or keyboard).\n- when the preview part is double-clicked.\n\nTo change the mode to \"double-click\", set the `activationMode: 'dblclick'`\nproperty in the machine's context.\n\n```jsx {2}\nconst service = useMachine(editable.machine, {\n  activationMode: \"dblclick\",\n})\n```\n\n### Usage with Textarea\n\nThe editable machine supports using a `textarea` instead of an `input` field.\nWhen a textarea is used, the editable will commit the value on `Cmd + Enter` or\n`Ctrl + Enter`.\n\n> Use the `api.inputProps` to spread the input props to the textarea element.\n> You might need to cast the input props to the correct type.\n\n```tsx {2}\n<textarea {...(api.inputProps as HTMLTextareaProps<HTMLTextareaElement>)} />\n```\n\n## Styling guide\n\nEarlier, we mentioned that each editable part has a `data-part` attribute added\nto them to select and style them in the DOM.\n\n### Focused state\n\nWhen the editable is in the focused mode, we set a `data-focus` attribute on the\n\"area\" part.\n\n```css\n[data-part=\"area\"][data-focus] {\n  /* CSS for the editable's focus state */\n}\n```\n\n### Empty state\n\nWhen the editable's value is empty, we set a `data-empty` attribute on the\n\"area\" part.\n\n```css\n[data-part=\"area\"][data-empty] {\n  /* CSS for the editable's focus state */\n}\n```\n\n### Disabled state\n\nWhen the editable is disabled, we set a `data-disabled` attribute on the \"area\"\npart.\n\n```css\n[data-part=\"area\"][data-disabled] {\n  /* CSS for the editable's focus state */\n}\n```\n\n## Methods and Properties\n\n### Machine Context\n\nThe editable machine exposes the following context properties:\n\n**`ids`**\nType: `Partial<{ root: string; area: string; label: string; preview: string; input: string; control: string; submitTrigger: string; cancelTrigger: string; editTrigger: string; }>`\nDescription: The ids of the elements in the editable. Useful for composition.\n\n**`invalid`**\nType: `boolean`\nDescription: Whether the input's value is invalid.\n\n**`name`**\nType: `string`\nDescription: The name attribute of the editable component. Used for form submission.\n\n**`form`**\nType: `string`\nDescription: The associate form of the underlying input.\n\n**`autoResize`**\nType: `boolean`\nDescription: Whether the editable should auto-resize to fit the content.\n\n**`activationMode`**\nType: `ActivationMode`\nDescription: The activation mode for the preview element.\n\n- \"focus\" - Enter edit mode when the preview is focused\n- \"dblclick\" - Enter edit mode when the preview is double-clicked\n- \"click\" - Enter edit mode when the preview is clicked\n- \"none\" - Edit can be triggered programmatically only\n\n**`submitMode`**\nType: `SubmitMode`\nDescription: The action that triggers submit in the edit mode:\n\n- \"enter\" - Trigger submit when the enter key is pressed\n- \"blur\" - Trigger submit when the editable is blurred\n- \"none\" - No action will trigger submit. You need to use the submit button\n- \"both\" - Pressing `Enter` and blurring the input will trigger submit\n\n**`selectOnFocus`**\nType: `boolean`\nDescription: Whether to select the text in the input when it is focused.\n\n**`edit`**\nType: `boolean`\nDescription: Whether the editable is in edit mode.\n\n**`defaultEdit`**\nType: `boolean`\nDescription: Whether the editable is in edit mode by default.\n\n**`onEditChange`**\nType: `(details: EditChangeDetails) => void`\nDescription: Function to call when the edit mode changes.\n\n**`maxLength`**\nType: `number`\nDescription: The maximum number of characters allowed in the editable\n\n**`disabled`**\nType: `boolean`\nDescription: Whether the editable is disabled.\n\n**`readOnly`**\nType: `boolean`\nDescription: Whether the editable is read-only.\n\n**`required`**\nType: `boolean`\nDescription: Whether the editable is required.\n\n**`placeholder`**\nType: `string | { edit: string; preview: string; }`\nDescription: The placeholder text for the editable.\n\n**`translations`**\nType: `IntlTranslations`\nDescription: The translations for the editable.\n\n**`finalFocusEl`**\nType: `() => HTMLElement`\nDescription: The element to receive focus when the editable is closed.\n\n**`value`**\nType: `string`\nDescription: The controlled value of the editable.\n\n**`defaultValue`**\nType: `string`\nDescription: The initial value of the editable when rendered.\nUse when you don't need to control the value of the editable.\n\n**`onValueChange`**\nType: `(details: ValueChangeDetails) => void`\nDescription: Function to call when the value changes.\n\n**`onValueRevert`**\nType: `(details: ValueChangeDetails) => void`\nDescription: Function to call when the value is reverted.\n\n**`onValueCommit`**\nType: `(details: ValueChangeDetails) => void`\nDescription: Function to call when the value is committed.\n\n**`dir`**\nType: `\"ltr\" | \"rtl\"`\nDescription: The document's text/writing direction.\n\n**`id`**\nType: `string`\nDescription: The unique identifier of the machine.\n\n**`getRootNode`**\nType: `() => Node | ShadowRoot | Document`\nDescription: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.\n\n**`onPointerDownOutside`**\nType: `(event: PointerDownOutsideEvent) => void`\nDescription: Function called when the pointer is pressed down outside the component\n\n**`onFocusOutside`**\nType: `(event: FocusOutsideEvent) => void`\nDescription: Function called when the focus is moved outside the component\n\n**`onInteractOutside`**\nType: `(event: InteractOutsideEvent) => void`\nDescription: Function called when an interaction happens outside the component\n\n### Machine API\n\nThe editable `api` exposes the following methods:\n\n**`editing`**\nType: `boolean`\nDescription: Whether the editable is in edit mode\n\n**`empty`**\nType: `boolean`\nDescription: Whether the editable value is empty\n\n**`value`**\nType: `string`\nDescription: The current value of the editable\n\n**`valueText`**\nType: `string`\nDescription: The current value of the editable, or the placeholder if the value is empty\n\n**`setValue`**\nType: `(value: string) => void`\nDescription: Function to set the value of the editable\n\n**`clearValue`**\nType: `VoidFunction`\nDescription: Function to clear the value of the editable\n\n**`edit`**\nType: `VoidFunction`\nDescription: Function to enter edit mode\n\n**`cancel`**\nType: `VoidFunction`\nDescription: Function to exit edit mode, and discard any changes\n\n**`submit`**\nType: `VoidFunction`\nDescription: Function to exit edit mode, and submit any changes\n\n### Data Attributes\n\n**`Area`**\n\n**`data-scope`**: editable\n**`data-part`**: area\n**`data-focus`**: Present when focused\n**`data-disabled`**: Present when disabled\n**`data-placeholder-shown`**: Present when placeholder is shown\n\n**`Label`**\n\n**`data-scope`**: editable\n**`data-part`**: label\n**`data-focus`**: Present when focused\n**`data-invalid`**: Present when invalid\n**`data-required`**: Present when required\n\n**`Input`**\n\n**`data-scope`**: editable\n**`data-part`**: input\n**`data-disabled`**: Present when disabled\n**`data-readonly`**: Present when read-only\n**`data-invalid`**: Present when invalid\n**`data-autoresize`**: \n\n**`Preview`**\n\n**`data-scope`**: editable\n**`data-part`**: preview\n**`data-placeholder-shown`**: Present when placeholder is shown\n**`data-readonly`**: Present when read-only\n**`data-disabled`**: Present when disabled\n**`data-invalid`**: Present when invalid\n**`data-autoresize`**: \n\n## Accessibility\n\n### Keyboard Interactions\n\n**`Enter`**\nDescription: Saves the edited content and exits edit mode.\n\n**`Escape`**\nDescription: Discards the changes and exits edit mode.","package":"@zag-js/editable","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/editable.mdx"}