Skip to main content
BETA
View Zag.js on Github
Join the Discord server

Editable

Editable is an input field used for editing a single line of text. It renders as static text and transforms into a text input field when then edit interaction is triggered (click, focus, or double-click).

Enter text...
Properties

Features

  • Use custom controls for the editable.
  • Pressing Enter commits the input value.
  • Pressing Esc reverts the value.
  • Activate edit mode by double-clicking or focusing on the preview text.
  • Auto-resize input to fit content

Installation

To use the editable machine in your project, run the following command in your command line:

npm install @zag-js/editable @zag-js/react # or yarn add @zag-js/editable @zag-js/react

This command will install the framework agnostic editable logic and the reactive utilities for your framework of choice.

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.

On a high level, the editable consists of:

  • Root: The root container for the editable.
  • Area: The container that wraps the preview and input.
  • Preview: The readonly element that displays the value.
  • Input: The input used to edit the value.

If you're going to use custom controls to trigger edit, save and cancel, you'll need these parts:

  • Edit Button: The button to trigger the edit mode.
  • Submit Button: The button to submit or save the value.
  • Cancel Button: The button to cancel and revert to previous value.

Usage

First, import the editable package into your project

import * as editable from "@zag-js/editable"

The editable package exports two key functions:

  • machine — The state machine logic for the editable widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

You'll need to provide a unique id to the useSetup hook. This is used to ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the editable machine in your project 🔥

import * as editable from "@zag-js/editable" import { useMachine, normalizeProps } from "@zag-js/react" export default function Editable() { const [state, send] = useMachine(editable.machine({ id: "1" })) const api = editable.connect(state, send, normalizeProps) return ( <div {...api.rootProps}> <div {...api.areaProps}> <input {...api.inputProps} /> <span {...api.previewProps} /> </div> </div> ) }

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 * as editable from "@zag-js/editable" import { useMachine } from "@zag-js/react" export default function Editable() { const [state, send] = useMachine(editable.machine({ id: "1" })) const api = editable.connect(state, send) return ( <div {...api.rootProps}> <div {...api.areaProps}> <input {...api.inputProps} /> <span {...api.previewProps} /> </div> <div> {!api.isEditing && <button {...api.editButtonProps}>Edit</button>} {api.isEditing && ( <div> <button {...api.submitButtonProps}>Save</button> <button {...api.cancelButtonProps}>Cancel</button> </div> )} </div> </div> ) }

Auto-resizing the editable

To auto-grow the editable as the content changes, pass the autoResize: true property to the machine's context.

const [state, send] = useMachine( editable.machine({ autoResize: true, }), )

Please note that, in this mode, the input and preview elements should not have any styles. Instead, pass the styles to the "area" element.

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 property of the machine's context to the desired value.

const [state, send] = useMachine( editable.machine({ autoResize: true, maxWidth: "320px", }), )

When the editable reaches the specified max-width, it'll clip the preview text with an ellipsis.

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", set the activationMode: 'dblclick' property in the machine's context.

const [state, send] = useMachine( editable.machine({ activationMode: "dblclick", }), )

Methods and Properties

The editable's api method exposes the following methods:

  • isEditing — Whether the editable is in the edit mode.
  • value — The current value of the editable.
  • setValue() — Function to set the value of the editable.
  • edit() — Function to take the editable into edit mode.
  • cancel() — Function to cancel the current editing session.
  • submit() — Function to commit or save the value.
const api = connect(state, send) api.isEditing // => false api.isValueEmpty // => false api.edit() api.setValue("Kakashi Sensei") api.submit() api.cancel()

Styling guide

Earlier, we mentioned that each editable part has a data-part attribute added to them to select and style them in the DOM.

Focused state

When the editable is in the focused mode, we set a data-focus attribute on the "area" part.

[data-part="area"][data-focus] { /* CSS for the editable's focus state */ }

Empty state

When the editable's value is empty, we set a data-empty attribute on the "area" part.

[data-part="area"][data-empty] { /* CSS for the editable's focus state */ }

Disabled state

When the editable is disabled, we set a data-disabled attribute on the "area" part.

[data-part="area"][data-disabled] { /* CSS for the editable's focus state */ }

Edit this page on GitHub

On this page