RZREDZ.UI

Inline edit

A value changed where it shows - a title in a list, a name on a page - behind a real Edit button, in a small form of its own that saves or cancels.

Examples

The value has an id; the Edit button names the form by commandfor with command="--edit"; the form, of class inline-edit-form, names the value by data-for and holds the field, its Save button and a Cancel button with command="--cancel". --edit shows the form in place of the value, the field focused and its text selected; Enter saves, Esc or Cancel puts the field back, and the focus returns to the Edit button. A click elsewhere leaves the form open.

Excursions

North Bay: marine park by speedboat
Night market and street food
<section class="card" aria-labelledby="inline-edit-row-title">
	<div class="card-header"><h2 class="fs-14" id="inline-edit-row-title">Excursions</h2></div>
	<div class="list-group list-group-flush">
		<div class="list-group-item hstack gap-8">
			<span class="table-title flex-fill" id="inline-edit-row-1">North Bay: marine park by speedboat</span>
			<button class="btn btn-sm btn-icon btn-text" type="button" commandfor="inline-edit-row-1-form" command="--edit" aria-label="Edit the title: North Bay"><i class="bi bi-pencil" aria-hidden="true"></i></button>
			<form class="inline-edit-form flex-fill" id="inline-edit-row-1-form" data-for="inline-edit-row-1" hidden>
				<input class="form-control form-control-sm" name="title" value="North Bay: marine park by speedboat" aria-label="Title" required>
				<button class="btn btn-sm btn-primary" type="submit">Save</button>
				<button class="btn btn-sm" type="button" commandfor="inline-edit-row-1-form" command="--cancel">Cancel</button>
				<div class="invalid-feedback" hidden></div>
			</form>
		</div>
		<div class="list-group-item hstack gap-8">
			<span class="table-title flex-fill" id="inline-edit-row-2">Night market and street food</span>
			<button class="btn btn-sm btn-icon btn-text" type="button" commandfor="inline-edit-row-2-form" command="--edit" aria-label="Edit the title: Night market"><i class="bi bi-pencil" aria-hidden="true"></i></button>
			<form class="inline-edit-form flex-fill" id="inline-edit-row-2-form" data-for="inline-edit-row-2" data-docs-save hidden>
				<input class="form-control form-control-sm" name="title" value="Night market and street food" aria-label="Title">
				<button class="btn btn-sm btn-primary" type="submit">Save</button>
				<button class="btn btn-sm" type="button" commandfor="inline-edit-row-2-form" command="--cancel">Cancel</button>
				<div class="invalid-feedback" hidden></div>
			</form>
		</div>
	</div>
</section>

Saved by the page

The form's submit fires redz:save on it, with the form and the field's value. A page that saves cancels it and answers with a promise: the Save button is busy until it settles - resolved, the value shows the saved text and the form closes; rejected with words, the form stays open, the field marked invalid and the words in its invalid-feedback, said at once. Left alone, the value shows the text and the field keeps it. The second row above answers after 600 ms and refuses an empty title.

document.addEventListener('redz:save', (event) => {
	event.preventDefault();
	event.detail.respondWith(fetch(event.detail.form.action, {method: 'POST', body: new FormData(event.detail.form)})
		.then((answer) => answer.ok ? answer.text() : answer.text().then((words) => Promise.reject(words))));
});

Inside another form

A form cannot sit in a form: where the value lives in one - a settings page with a save bar - the edit form is a popover="manual" placed outside it, with the class menu for its panel; --edit opens it beside the Edit button.

Example Cruises
<div class="hstack gap-8">
	<span class="fs-16 fw-600" id="inline-edit-popover-name">Example Cruises</span>
	<button class="btn btn-sm btn-icon btn-text" type="button" commandfor="inline-edit-popover-form" command="--edit" aria-label="Edit the company's name"><i class="bi bi-pencil" aria-hidden="true"></i></button>
</div>
<form class="menu inline-edit-form" id="inline-edit-popover-form" data-for="inline-edit-popover-name" popover="manual">
	<input class="form-control form-control-sm" name="company" value="Example Cruises" aria-label="The company's name" required>
	<button class="btn btn-sm btn-primary" type="submit">Save</button>
	<button class="btn btn-sm" type="button" commandfor="inline-edit-popover-form" command="--cancel">Cancel</button>
	<div class="invalid-feedback" hidden></div>
</form>

Keyboard and accessibility

KeyDoes
Enter, Space on EditOpens the form, the focus in the field, its text selected
Enter in the fieldSaves
EscPuts the field back and closes the form, the focus on Edit
  • Edit is a real button named after what it edits - the value's own text may be a link to its record and stays one.
  • The form saves only by its Save button or Enter: a blur never commits half an edit, and never throws one away.
  • A refused save keeps the focus in the field; invalid-feedback takes role="alert", so the page's words are said at once, and the field names it in aria-describedby.

Tokens

From css/components/inline-edit.css, which declares no custom property of its own.

It reads the theme's --redz-space-8, --redz-space-12.