Editable
Inline edit: a focusable preview that swaps to an input, submitting on Enter/blur and cancelling on Escape.
| Package | @vizejs/ui/editable |
| Maturity | stable |
| Own the source | vize lib pull editable |
| Requires | context, controllable-state, id |
| Aliases | inline edit, click to edit, editable text, in-place editor |
| Covers | Chakra Editable, Ark UI Editable, Reka UI Editable |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { Editable, EditablePreview, EditableInput, EditableTrigger } from "@vizejs/ui/editable";
Or copy the source into your project with vize lib pull editable (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- Inline-editable document title with explicit edit, save, and cancel buttons. -->
<script setup lang="ts">
import { ref } from "vue";
import { Editable, EditableInput, EditablePreview, EditableTrigger } from "@vizejs/ui/editable";
const title = ref("Quarterly planning notes");
</script>
<template>
<div>
<Editable
v-model="title"
name="title"
aria-label="Document title"
placeholder="Untitled document"
activation-mode="dblclick"
:max-length="80"
>
<EditablePreview />
<EditableInput />
<EditableTrigger action="edit">Rename</EditableTrigger>
<EditableTrigger action="submit">Save</EditableTrigger>
<EditableTrigger action="cancel">Cancel</EditableTrigger>
</Editable>
<p>Saved title: {{ title }}</p>
</div>
</template>
API
Editable
Source: src/families/form/editable/editable.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string | null |
undefined |
Id of the edit input. null and undefined select a deterministic fallback. |
name |
string |
undefined |
Native form field name; a hidden input submits the committed value. |
modelValue |
string |
undefined |
Controlled committed value. undefined selects uncontrolled behavior. |
defaultValue |
string |
"" |
Initial uncontrolled value. |
editing |
boolean |
undefined |
Controlled edit mode (v-model:editing). undefined selects uncontrolled behavior. |
defaultEditing |
boolean |
false |
Initial uncontrolled edit mode. |
activationMode |
EditableActivationMode |
"focus" |
How the preview enters edit mode. Enter and F2 on a focused preview always do. |
submitMode |
EditableSubmitMode |
"both" |
Which interactions commit the draft: Enter, blur, both, or only an explicit submit. |
selectOnFocus |
boolean |
true |
Select the input text when edit mode starts. |
placeholder |
string |
undefined |
Text shown by the preview and input while empty. |
maxLength |
number |
undefined |
Native maximum length of the input. |
disabled |
boolean |
false |
Prevent editing and remove the preview from the tab order. |
readOnly |
boolean |
false |
Show the value without allowing edit mode. |
ariaLabel |
string |
undefined |
Accessible name of the input when no label or aria-labelledby supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the input and preview. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe the input. |
ariaErrormessage |
string |
undefined |
Id of the validation error message used while invalid. |
ariaInvalid |
EditableAriaInvalid |
false |
Invalid state announced on the input. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
[value: string] |
Fired when a submit requests a new committed value. |
update:editing |
[editing: boolean] |
Fired when edit mode requests to open or close (v-model:editing). |
edit |
[] |
Fired when edit mode starts. |
submit |
[value: string, previous: string] |
Fired after a submit with the committed value and the previous value. |
cancel |
[value: string, discarded: string] |
Fired after a cancel with the restored value and the discarded draft. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
EditableSlotState |
Renders the preview, input, and triggers with the editing state. |
Exposed
| Member | Type | Description |
|---|---|---|
value |
string |
Committed value. |
draft |
string |
Text in the input while editing (equals value otherwise). |
editing |
boolean |
Whether the input is shown. |
empty |
boolean |
Whether the committed value is empty (the preview shows the placeholder). |
disabled |
boolean |
Whether editing is disabled. |
readOnly |
boolean |
Whether the value can be read but not edited. |
state |
EditableState |
Stable state token. |
root |
HTMLDivElement | null |
Rendered root element. |
edit |
() => boolean |
Enter edit mode (no-op while disabled or read-only); returns whether it started. |
submit |
() => boolean |
Commit the draft and leave edit mode; returns whether the value changed. |
cancel |
() => void |
Discard the draft and leave edit mode. |
setValue |
(value: string) => boolean |
Replace the committed value; returns whether it changed. |
EditablePreview
Source: src/families/form/editable/editable-preview.vue
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
{ readonly value: string; readonly empty: boolean } |
Preview contents; defaults to the value or the placeholder. |
EditableInput
Source: src/families/form/editable/editable-input.vue
EditableTrigger
Source: src/families/form/editable/editable-trigger.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
action (required) |
EditableTriggerAction |
required |
What activation does: enter edit mode, submit the draft, or cancel it. |
ariaLabel |
string |
undefined |
Accessible name when the contents are icon-only. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
{ readonly editing: boolean } |
Trigger contents with the current editing state. |
Behavior
Normative state x input -> outcome table for editable.vue,
editable-preview.vue, editable-input.vue, and editable-trigger.vue
(@vizejs/ui/editable). Every row is proven by the named test in
editable.test.ts or editable-ssr.test.ts; compile-only assertions live in
editable.types.test-d.ts.
| # | State | Input | Outcome | Proven by |
|---|---|---|---|---|
| E1 | preview, named | render | focusable role="button" preview with the value; input and submit/cancel triggers are hidden; hidden form value |
renders a focusable preview with the input and editing triggers hidden |
| E2 | preview, focus mode |
focus preview | enters edit mode, emits update:editing then edit, focuses the input and selects its text |
focusing the preview enters edit mode and focuses the selected input |
| E3 | editing | Enter / Escape | Enter commits (submit(value, previous)), Escape discards (cancel(value, discarded)); focus returns to the preview without reopening |
Enter submits, Escape cancels, and focus returns to the preview without reopening |
| E4 | editing, submitMode |
blur / Enter | both (default) submits on blur and Enter; enter ignores blur; none requires an explicit submit |
blur submits by default and submitMode controls Enter and blur |
| E5 | activationMode="none" |
triggers | focus and clicks no longer activate (Enter/F2 still do); edit/submit/cancel triggers act, and pointer presses keep focus in the input | triggers edit, submit, and cancel while keeping focus in the input |
| E6 | click / dblclick modes | click / dblclick / F2 | the preview activates only on its mode; Enter and F2 always activate a focused preview | click and double-click activation modes |
| E7 | controlled | focus / submit | controlled editing and modelValue win until the parent accepts them |
controlled value and editing win until the parent accepts them |
| E8 | empty / disabled / read-only | render / activation | placeholder shows when empty; disabled and read-only previews stay focusable with aria-disabled, triggers are disabled, and nothing is emitted |
placeholder, disabled, and read-only states |
| E9 | in a form / imperative | submit / expose | the hidden input submits the committed value; edit, submit, cancel, setValue, and state are exposed |
submits the committed value with a form and exposes edit, submit, cancel, setValue |
| E10 | part without provider | setup | throws the stable VIZE_UI_CONTEXT_MISSING: Editable diagnostic |
parts require an Editable provider |
| E11 | SSR / hydration | isolated requests | byte-identical markup with hidden parts, hydration without diagnostics, and interactive preview |
renders byte-identical inline-edit markup and hydrates without mismatches |
Public extension contract
| Surface | Contract |
|---|---|
| Parts | root, preview, input, and edit-trigger / submit-trigger / cancel-trigger. |
| Data attributes | data-vize-ui, data-state (preview/editing/readonly/disabled), data-empty, trigger data-action. |
| Visibility | Parts toggle the native hidden attribute, so SSR markup and hydration never swap nodes. |
The subpath is tree-shakable and ships no CSS; those package contracts are
pinned by distribution.test.ts, check:size, and check:tree-shaking.