Skip to content

Editable ​

SEditable shows a value as plain text and turns it into an input in place. It is built on Reka UI (activation, commit and cancel, the hidden input for native form submission) and reuses SFormField (label, hint, error message, a11y) and SButton for the optional controls. The value is bound with v-model.

Prefer it to an always-visible field when the value is mostly read and rarely corrected — a document title, a name in a list row, a cell in a table — so the page reads as content instead of as a form. When the value is meant to be filled in, use SInput: a field that announces itself is easier to find and to fill.

The box never changes size between the two states: the frame, its padding and its border width stay the same and only the colors change, so nothing on the page moves when editing starts.

Keyboard and screen readers. The value is a tab stop. With the default activation-mode="focus" reaching it opens the editor; in dblclick mode press Enter or Space (or double-click). Enter commits the value, Escape discards the edit, and focus returns to the value afterwards instead of falling to the page. The input carries the field label, so it is announced like any other field; with with-controls the buttons give assistive technology and touch users an explicit affordance, which a double click alone does not.

Basic usage ​

Tab into the text or click it: the value becomes an input with the same box. Enter or clicking away commits it, Escape restores it.

Quarterly report
Click the title to rename it

With controls ​

with-controls adds the edit, save and cancel buttons. Their accessible names come from the locale dictionary and can be replaced one by one (edit-label, save-label, cancel-label); the controls slot replaces the whole row and receives { isEditing, edit, submit, cancel }.

Not set

Activation and commit ​

activation-mode decides what opens the editor: focus (the default), dblclick or none — with none only the controls and the exposed edit() do. submit-mode decides what commits the value: enter, blur, both (the default) or none, where leaving the field discards the edit. Escape cancels in every mode.

Call back on Monday
Call back on Monday
Call back on Monday

As a title in a card ​

Without a label the field is just the text, which is what a card heading or a list row needs. auto-resize makes the box follow the text instead of the row, size sets its type scale, and the preview slot renders the value however the row needs it.

Design system
Draft
Q3
Internal

Validation ​

rules checks the value when focus leaves the field, and then on every change while the error is shown; inside SForm the field is also checked on submit, and the form moves focus to it — to the text when the editor is closed, to the input when it is open. name adds the value to native form submission. See the Validation guide for the details.

Submit with an empty name, then type one.

Click to name the project

API ​

Props

NameTypeDefaultDescription
idstringundefinedField id. Generated automatically when not set (SSR-safe).
labelstringundefinedField label (linked to the input via for/id).
hintstringundefinedHint below the field.
errorstringundefinedError message. When set, the field is marked invalid.
invalidbooleanfalseExplicitly marks the field invalid (in addition to error).
requiredbooleanfalseMarks the field as required: adds * to the label, aria-required to the input and required to the hidden form input (rendered inside a <form> when name is set). The input itself carries no native required: it is hidden outside the edit view, and a hidden invalid control would stall the submit instead of pointing at anything.
placeholderstringundefinedText shown instead of an empty value, in the preview and as the input placeholder. Consumer content: it is not taken from the locale dictionary.
size"md" | "sm" | "lg""md"Field size: sm (32px), md (40px) or lg (48px).
disabledbooleanfalseDisables the field: the value stays visible but the editor never opens.
readonlybooleanfalseRead-only field: the value is visible and selectable, but the editor never opens.
squarebooleanfalseSquare corners: removes the field border radius (rounded by default).
activation-mode | "none" | "focus" | "dblclick""focus"What opens the editor: focus (entering the preview with Tab or a click), dblclick (a double click) or none (only the controls and the exposed edit()). Enter and Space on the focused preview open it in every mode but none.
submit-mode | "none" | "blur" | "both" | "enter""both"What commits the value: enter (the Enter key), blur (focus leaving the field), both (the default) or none — with none the value is committed only by the submit control or the exposed submit(), and leaving the field discards the edit. Escape always cancels.
max-lengthnumberundefinedMaximum number of characters accepted by the input.
auto-resizebooleanfalseThe field takes the width of its value instead of the whole row: the value and the input share one grid cell. Typing does not widen the box — the input scrolls, as any field does.
select-on-focusbooleanfalseSelects the whole value when the editor opens, so typing replaces it.
start-with-edit-viewbooleanfalseOpens the editor on mount, with the input focused.
with-controlsbooleanfalseRenders the edit, save and cancel buttons next to the value.
edit-labelstringundefinedAccessible name of the edit button (defaults to the locale dictionary).
save-labelstringundefinedAccessible name of the save button (defaults to the locale dictionary).
cancel-labelstringundefinedAccessible name of the cancel button (defaults to the locale dictionary).
aria-labelstringundefinedAccessible name of the input, for a field rendered without a label.
namestringundefinedName of the value in native form submission: renders a hidden input inside a <form>.
rulesreadonlyundefinedValidation rules: functions of the value that return true or the error text, run in order until the first failure. See Validation.
validate-on"blur" | "input" | "submit"undefinedWhen the field checks its rules: blur (after the user leaves the field, then on every change while an error is shown), input (on every change) or submit (only on form submission and validate()). Overrides validate-on of SForm; blur by default.
model-valuestring""The committed text value. Two-way binding via v-model.

Events

NameSignatureDescription
update:modelValue(value: string) => voidEmitted when modelValue changes. Used for two-way binding (v-model).
cancel() => voidEditing has been dropped (Escape or the cancel control); the value is unchanged.
blur(event: FocusEvent) => voidFocus left the field. Moving between the value and the controls does not count.
submit(value: string) => voidThe value has been committed; carries the new value.
focus(event: FocusEvent) => voidFocus entered the field. Moving between the value and the controls does not count.
edit() => voidThe editor has been opened.

Slots

NameDescription
previewThe value as it is shown at rest, instead of plain text. Receives { value, isEditing }; the placeholder is drawn by the field itself when the value is empty.
controlsReplaces the default row of buttons (with-controls). Receives { isEditing, edit, submit, cancel }.