Skip to content

HyInlineEdit

Usage examples on this page are written for Lit / plain HTML (<hy-inline-edit>). The same component ships as HyInlineEdit in @whitespaceux/harmony-react (native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.

Click-to-edit text: a display ⇄ edit swap with an async commit lifecycle.

The value of this component is encapsulating the error-prone commit logic — Enter / Escape / blur-commit with a relatedTarget guard, optional confirm/cancel buttons, async validation that keeps the edit view open, and an optimistic-commit-then-rollback contract via a cancelable change event. It is editor-agnostic: the default editor is hy-text-input, but any hy-* form control can be slotted into editor.

Key Features:

  • trigger: click / dblclick / manual (pencil button or programmatic)
  • affordance: hover / always / nonenone drops the pencil and makes the text itself the control (Tab, Enter / Space, a hover outline the focus ring recolours)
  • hint: a tooltip over the display view ("Select to rename") — the spoken cue where no glyph says the text is editable
  • emphasis: outlined (the hy-text-input control) / plain (seamless: a bare input in the text's own box — same font, same line, width = its text — so the display ⇄ edit swap moves nothing; the Google Docs title)
  • submit-on: blur / enter / confirm (Escape always reverts)
  • Editor-agnostic editor slot (defaults to hy-text-input)
  • validate keeps the edit view open with an inline error
  • loading + cancelable change → optimistic update with rollback
  • Display ≠ edit: the default slot renders formatted display; the editor edits the raw value

Examples

Basic rename

html
<hy-inline-edit value="Untitled"></hy-inline-edit>

Text-only title (no pencil) — a document name in a header

html
<hy-inline-edit
  value="Untitled"
  affordance="none"
  hint="Select to rename"
  label="Document name"
  submit-on="confirm"
>
  <span class="hy-typography" data-hy-style="title-xs">Untitled</span>
</hy-inline-edit>

Seamless title — no pencil, no buttons, no layout shift (Google Docs)

html
<!-- The typography sits on the HOST so the plain editor inherits it too. -->
<hy-inline-edit
  class="hy-typography"
  data-hy-style="title-xs"
  value="Untitled"
  affordance="none"
  emphasis="plain"
  submit-on="blur"
  hint="Select to rename"
  label="Document name"
></hy-inline-edit>

Async commit with rollback

javascript
<hy-inline-edit value="Untitled" submit-on="blur"></hy-inline-edit>
<script>
el.addEventListener('change', (e) => {
e.preventDefault();            // keep the edit view open
el.loading = true;
save(e.detail.value).then(
() => { el.value = e.detail.value; el.editing = false; el.loading = false; },
() => { el.loading = false; } // stay open on failure
);
});
</script>

API

Properties

PropertyAttributeTypeDefaultDescription
valuevaluestring | undefinedThe committed value.
editingeditingbooleanfalseControlled open state of the edit view.
triggertrigger'click' | 'dblclick' | 'manual''click'How edit mode opens.
submitOnsubmit-on'blur' | 'enter' | 'confirm''blur'When a draft is committed.
affordanceaffordance'hover' | 'always' | 'none''hover'When the edit affordance (pencil) is visible. hover reveals it on hover / focus (ideal for dense lists where a persistent pencil per row is clutter); always keeps it visible at rest (prominent single fields where editability must be discoverable); none renders no pencil at all and makes the text itself the control — a button reachable by Tab, opened by click / Enter / Space, an outline on hover, recoloured by focus, standing in for the glyph, focus handed back to it after Enter / Escape / the confirm buttons. The shape of a document or page title in a header (Google Docs, Notion, Atlassian's inline edit); it needs a trigger other than manual to be reachable.
loadingloadingbooleanfalseAsync pending — shows a spinner, disables the editor.
placeholderplaceholderstring | undefinedEmpty-value placeholder shown in the display view.
disableddisabledbooleanfalseWhether the control is disabled.
labellabelstring | undefinedAccessible label forwarded to the default editor.
emphasisemphasis'outlined' | 'plain''outlined'The default editor's chrome. outlined (default) is the hy-text-input control — a full form control with its own height and padding. plain is the seamless editor: a bare input inheriting the host's font, size, weight, letter-spacing and line-height, no padding / border / background, width sized to its text (a hidden mirror span), the focus ring its only chrome — so the display ⇄ edit swap changes nothing around it. A click opens it with the caret where the click landed; with affordance="none" keyboard focus opens it directly with everything selected (Tab onto the name and type to replace — no Enter first). Put the typography on the host (not on a slotted span) so both views read it. A slotted editor wins over either.
hinthintstring | undefinedTooltip shown over the display view on hover / focus (e.g. "Select to rename"). The display view is wrapped in an hy-tooltip only while the hint is set, and never while editing. Pairs with affordance="none", where no glyph says the text is editable; the tooltip also becomes the trigger's accessible description.
validateInlineEditValidator | undefinedValidator run before commit; a returned message keeps the edit view open. Property-only.

Events

EventDetailDescription
edit-startFired when the edit view opens. Detail: {}
changeCommit. Cancelable — preventDefault() keeps the edit view open. Detail: { value: string }
cancelFired when editing is canceled (Escape / cancel button). Detail: {}

Slots

SlotDescription
defaultThe display rendering of the rest state (formatted). Falls back to value / placeholder.
editorThe edit control (defaults to hy-text-input, or a bare input under emphasis="plain"); a slotted editor wins over both.
edit-triggerThe pencil / edit affordance (defaults to a hy-icon-button). Not rendered under affordance="none".

CSS Parts

PartDescription
displayThe display-view wrapper.
editThe edit-view wrapper.
errorThe inline validation error.

Built with Lit. Documented with VitePress.