Demo
Changes save instantly in this demo
Website-style Edit profile section with multiple inline editors. Each row supports focus trapping while active, Enter to save, and Escape to cancel.
Edit profile
Update the public details shown on your profile page.
Display name
Headline
Location
Website
Username
Pronouns
Alpine.js Inline Editor
huxInlineEditor manages the behavior switch between static display and inline editing. It keeps committed input state, supports commit/revert keyboard shortcuts, and traps focus within the active editor controls.
Runtime Constraints
- No special runtime requirements beyond Alpine.js.
- For robust keyboard behavior, keep all editable controls inside the focus-trap container ref.
- Prefer
x-show+x-cloak+x-transitionfor read/edit toggles because it keeps DOM elements connected (improving focus restoration reliability) and provides smoother visual transitions. x-ifis supported, but when toggling with DOM removal you should configurereturnFocusTemplateReffor consistent focus return.
API
huxInlineEditor(config)
Returns an Alpine data object with:
isEditing: booleaninputValue: stringdraftValue: stringeditorId: string | nullhasChanges: booleanenterEditMode(): voidcommitChanges(): voidrevertChanges(): voidregisterInput(targetElement: HTMLInputElement | HTMLTextAreaElement): voidhandleInputFocus(event: FocusEvent): voidhandleInputKeydown(event: KeyboardEvent): voidtrapFocus(event: KeyboardEvent): void
Internal helper methods are private implementation details and are not part of the supported API contract.
Options
inputValue: string(default:'') Initial committed input value and initial draft value.editorId: string(optional) Adds scoped events:hux-inline-editor:{editorId}:commitandhux-inline-editor:{editorId}:revert.inputTemplateRef: string(default:'inlineEditorInput')x-refused for auto-focus and select-all behavior in edit mode.focusTrapTemplateRef: string(default:'inlineEditor')x-refused as the keyboard focus-trap root while editing.returnFocusTemplateRef: string(optional) Optionalx-refused as the primary focus return target after commit/revert. If the previously focused element is disconnected, focus attempts this ref first. If unavailable, focus falls back to the first visible focusable element in DOM order within the component.
Quick Start
<div x-data="huxInlineEditor({ inputValue: 'Ada Lovelace' })">
<div x-show="!isEditing" x-cloak x-transition.opacity>
<span x-text="inputValue"></span>
<button type="button" x-on:click="enterEditMode()">Edit</button>
</div>
<div
x-show="isEditing"
x-cloak
x-transition.opacity
x-ref="inlineEditor"
x-on:keydown="trapFocus($event)"
>
<label>
<span class="sr-only">Profile name</span>
<input
x-ref="inlineEditorInput"
x-model="draftValue"
type="text"
x-init="registerInput($el)"
aria-describedby="profile-name-inline-editor-help"
x-on:focus="handleInputFocus($event)"
x-on:keydown="handleInputKeydown($event)"
/>
</label>
<button type="button" x-on:click="commitChanges()">Save</button>
<button type="button" x-on:click="revertChanges()">Cancel</button>
</div>
<p id="profile-name-inline-editor-help">
Press Enter to save, Escape to cancel, and Tab to cycle within editor controls.
</p>
</div>Common Usage Patterns
Listen for commit events
<div
x-data="huxInlineEditor({ editorId: 'profile-name', inputValue: 'Ada Lovelace' })"
x-on:hux-inline-editor:profile-name:commit.window="console.log($event.detail.inputValue)"
>
...
</div>Configure an explicit return-focus target
<div x-data="huxInlineEditor({ inputValue: 'Ada Lovelace', returnFocusTemplateRef: 'editButton' })">
<button type="button" x-ref="editButton" x-on:click="enterEditMode()">Edit</button>
...
</div>Commit and revert with keyboard
<input
x-ref="inlineEditorInput"
x-model="draftValue"
type="text"
x-init="registerInput($el)"
aria-describedby="profile-name-inline-editor-help"
x-on:focus="handleInputFocus($event)"
x-on:keydown="handleInputKeydown($event)"
/>Behavior Contract
enterEditMode()copiesinputValueintodraftValue, setsisEditing = true, focuses the configured input ref, and selects all text.registerInput()stores the active input/textarea element, focuses it, and selects all text.handleInputFocus()selects all text in the focused input/textarea.handleInputKeydown()commits onEnterand reverts onEscape.trapFocus()cyclesTabandShift+Tabinside the active focus-trap root while editing.commitChanges()setsinputValue = draftValue, exits edit mode, restores focus (previous active element, configured return-focus ref, or first visible focusable element in DOM order), and dispatches commit event(s).revertChanges()resetsdraftValue = inputValue, exits edit mode, restores focus (previous active element, configured return-focus ref, or first visible focusable element in DOM order), and dispatches revert event(s).
Error Handling
- If no input or textarea target can be resolved after focus retries, the component logs:
[huxInlineEditor] Unable to resolve input or textarea target for inlineEditorInput.by default. If you overrideinputTemplateRef, the logged value uses that configured ref name. - Missing optional listeners do not affect commit/revert behavior.
Accessibility Notes
- Use a real
button(type="button") to enter edit mode. - Keep editable controls within the focus-trap container to preserve keyboard containment while active.
- Keep visible labels for the editable field, or use an explicit
<label>for screen readers. - If you surface status updates, use an
aria-live="polite"region.
Notes
- Default event names:
hux-inline-editor:commithux-inline-editor:revert