Appearance
InlineEditable
Purpose
InlineEditable is a thin, headless UI wrapper over useInlineEdit.
It provides a consistent inline edit lifecycle:
- Display mode → start editing
- Edit mode → draft value
- Save / cancel
- Save loading + error state
- Optional Enter/Escape keyboard shortcuts
When to use
Use InlineEditable when:
- You’re editing a single value inline (rename, quick field edit)
- You want a consistent save/cancel lifecycle but custom markup
- Render-props are a good fit for your component structure
Prefer the hook (useInlineEdit) when:
- You need total control over state and rendering
- You’re editing multiple fields at once (inline “form”)
- You need to integrate with custom focus management
Example
tsx
import React from 'react'
import { InlineEditable } from '@/shared/ui/components/InlineEditable'
export function EditableName({ name }: { name: string }) {
return (
<InlineEditable
value={name}
onSave={async (next) => {
// await repository.updateName(next)
}}
renderDisplay={({ value, onStartEdit }) => (
<button type="button" onClick={onStartEdit}>
{value}
</button>
)}
renderEditor={({ value, onChange, onSave, onCancel, isSaving, inputProps, error }) => (
<div>
<input
value={value as string}
onChange={(e) => onChange(e.target.value)}
{...inputProps}
autoFocus
/>
<button type="button" onClick={onSave} disabled={isSaving}>
{isSaving ? 'Saving…' : 'Save'}
</button>
<button type="button" onClick={onCancel} disabled={isSaving}>
Cancel
</button>
{error && <p role="alert">Save failed.</p>}
</div>
)}
/>
)
}Props (concise)
value- The external value to display when not editing.
onSave(value)- Called when saving the draft. May be sync or async.
renderDisplay({ value, onStartEdit })- Render display mode; call
onStartEdit()to enter edit mode.
- Render display mode; call
renderEditor({ value, onChange, onSave, onCancel, isSaving, error, inputProps })- Render edit mode; use
inputProps.onKeyDownfor Enter/Escape handling.
- Render edit mode; use
enableKeyboardShortcuts- Defaults to
true. Enables Enter-to-save / Escape-to-cancel behavior (via the underlying hook).
- Defaults to
onCancel/onSaveSuccess/onSaveError- Lifecycle callbacks forwarded to
useInlineEdit.
- Lifecycle callbacks forwarded to
className- Optional wrapper class.
Notes / Gotchas
- External updates: when
valuechanges while not editing,InlineEditablesyncsoriginalValueso display stays up to date. - Draft typing: for non-string values, pass a typed
InlineEditable<T>and handle conversion in your editor. - Keyboard handling: for custom key behavior, you can ignore
inputPropsand handle key events yourself, but then you own save/cancel UX consistency.