InlineEditor

Click-to-edit text with async save, error display, optional input masks, and native input types.

InlineEditor is a client component that shows a value as text and switches to an editable field with save and cancel buttons. Use it for click-to-edit fields on detail pages. It uses react-textarea-autosize for multi-line editing and MaskedField when a mask preset is set.

Description
Edit
Quarterly roadmap for the design system team.

Import#

typescript
import { InlineEditor } from "@reactberry/system/blocks";

Usage#

typescript
"use client";

import { InlineEditor } from "@reactberry/system/blocks";
import { Box } from "@reactberry/system/elements";

async function saveField(id: string, text: string) {
  const res = await fetch(`/api/projects/${id}`, {
    method: "PATCH",
    body: JSON.stringify({ description: text }),
  });
  if (!res.ok) throw new Error("Could not save the description.");
}

export default function ProjectDescription({ project }: { project: { id: string; description: string | null } }) {
  return (
    <Box maxWidth="32rem">
      <InlineEditor
        id={project.id}
        label="Description"
        initialText={project.description}
        placeholder="Add a description"
        onSave={saveField}
      />
    </Box>
  );
}

Examples#

Masked phone number#

Set maskPreset to a key of maskPresets. The read-only text is formatted with the same mask.

Phone
(555) 123-4567

Native input and custom buttons#

inputType renders a single-line input, and buttonConfig sets props such as variant and aria-label on each button.

Email
Edit
ada@example.com

API#

InlineEditor#

PropTypeDefaultDescription
id
string | number
—

Passed to onSave as a string and used to build the error element id.

initialText
string | null
—

Current stored value.

placeholder
string
—

Field placeholder, also shown in italics when there is no value.

onSave*
(id: string, text: string) => Promise<void>
—

Called on save. Resolving exits edit mode; rejecting keeps the editor open and shows the error's message.

label
ReactNode
—

Header label. (Wait...) is appended while saving.

editLabel
string
—

Text shown next to the pencil icon on the edit button.

isDisabled
boolean
false

Disables the edit button, the read-only click target and the field.

fieldProps
Record<string, any>
{}

Spread onto the active field after its defaults.

containerProps
Record<string, any>
{}

Spread onto the outer Text (as="div").

headerProps
Record<string, any>
{}

Spread onto the header Group that holds the label and buttons.

controlSize
string
small

$size for the edit, save and cancel buttons.

buttonConfig
any
{…

Props spread onto each button, keyed edit, save and cancel. Passing it replaces the whole default object.

maskPreset
string
—

A key of maskPresets. A valid key renders a MaskedField and formats the read-only text with the same mask. Unknown keys are ignored.

inputType
string
—

Native input type (e.g. "email", "url", "tel"). Renders a single-line input instead of the autosizing textarea, so the browser applies its own keyboard and validation. Ignored when maskPreset resolves to a mask.

displayText
string | null
—

Text shown when not editing, for fields whose stored value is not the human-readable form (e.g. a date input's YYYY-MM-DD).

The default buttonConfig sets variant: "ghost" for edit, variant: "success" for save and variant: "default" for cancel. No other props are accepted.

Keyboard#

KeyAction
EnterorSpace

Opens the editor when the read-only value is focused.

Accessibility#

  • In read-only mode the value area has role="button" and tabIndex of 0. Both are removed when isDisabled is set.
  • Error messages render with role="alert" and are linked to the field through aria-describedby.
  • Save and cancel buttons contain only icons and have no aria-label; pass one through buttonConfig.save and buttonConfig.cancel.

Notes#

  • Error messages use the thrown Error's message, or "Something went wrong. Please try again.". Errors are also logged with console.error.
  • Passing buttonConfig replaces the whole default object. Omitted keys fall back to the inline defaults ("ghost" for edit and cancel, "outline.dark" for save).
  • There is no keyboard shortcut for saving or cancelling while editing.
  • The draft text resets to initialText whenever initialText changes or edit mode toggles.