Editable (inline edit)
Preview: Default
Click-to-edit text. Preview is a button ("Edit <label>"); Enter saves, Escape cancels, blur saves. `size` sets the preview's text style (heading vs body). Saving an empty value clears it unless `required`, which keeps the old value. Enter and Escape return focus to the preview.
Import
import { Editable } from '@marbleui/ui'Props
<Editable>
| Prop | Type | Default | Description |
|---|---|---|---|
| label *required | string | — | |
| onChange *required | (v: string) => void | — | |
| value *required | string | — | |
| className | string | — | |
| placeholder | string | 'Empty' | |
| required | boolean | — | |
| size | 'md' | 'lg' | 'md' |
Accessibility
Keyboard interaction, focus management and ARIA semantics come from the underlying primitives: React Aria Button · React Aria Input · React Aria TextField. Follow the primitive's docs for the full keyboard map.
Usage notes
Click-to-edit text for titles and short values that are read more often than changed. For a field that is always editable use TextField.
const [title, setTitle] = useState('Q4 planning')
<Editable size="lg" label="Title" value={title} onChange={setTitle} />
<Editable label="Description" placeholder="Add a description…" value={description} onChange={setDescription} />
- Controlled only:
valueandonChangeare required.onChangefires on save (even if nothing changed), not on each keystroke. - The preview is a button announced as “Edit Title: Q4 planning”. Enter or blur saves; Escape cancels. After Enter or Escape focus returns to the preview.
- Saved text is trimmed. An empty edit clears the value; with
requiredit restores the previous value instead. - Single line only.
size="lg"gives heading-sized text;placeholder(default “Empty”) shows when the value is blank.
Example source · show· hide
import { useState } from 'react'
import { Editable } from './editable'
function Demo() {
const [title, setTitle] = useState('Q4 planning')
const [desc, setDesc] = useState('')
return <div className="flex w-80 flex-col gap-2"><Editable size="lg" label="Title" value={title} onChange={setTitle} /><Editable label="Description" placeholder="Add a description…" value={desc} onChange={setDesc} /></div>
}
export const styles = { Default: Demo }Source: packages/ui/src/editable/editable.tsx
Catalog
- Category
- inputs
- Priority
- Extra
- Primitive
- composed
- React Aria
- TextField
- Base UI
- Input