# Editing values

> Letting people type freely into a field that must end up holding a valid value.

A field that holds a typed value — a number, a date, a measurement — has two
jobs that pull against each other: to let people type freely, and to end up
holding a valid value. Editing well means keeping the two apart: typing is
typing, and the value is settled only when people say they are done.

## Best practices

**Leave typing alone.** While people type, change nothing: do not reformat,
round, move the caret or report a problem. Text that is halfway to a value is not
an error.

**Read the value at commit.** People commit by pressing Return (Enter) or by
leaving the field. Only then is the text read; a value is constrained to what the
field allows and shown in its proper form, so people see what was kept.

**Do not read again what was not changed.** Text that is still the value as
shown is the value. Reading it back could only lose what the display leaves
out, such as digits beyond the precision shown.

**Leaving for another window is not leaving the field.** When another
application takes focus, what was being typed is still being typed on return;
nothing is committed, and nothing is marked wrong.

**Commit what was filled in.** Text that a browser or a password manager puts in
a field that does not have focus is committed as it arrives: no blur will follow
to commit it.

**Keep what could not be read.** When committed text is not a value, leave it as
typed and mark the field invalid, saying why. Correcting a slip is quicker than
typing again, and a field that silently restores its old value hides the mistake.

**Let Escape take an edit back.** Escape abandons what was typed and shows the
last value. When there is nothing to abandon, Escape belongs to whatever contains
the field — a popover, a dialog — so it must not be swallowed.

**Let the input method finish.** While an input method is composing, every key
belongs to it. Return confirms the composition; it does not commit the field.
The composed text is not read, replaced or judged until it is confirmed.

**Step with the arrow keys.** Up and Down Arrow change the value by a step; Shift
makes the step larger, and Option or Alt smaller where the type has a smaller
step. Stepping starts from what is typed, when it reads as a value.

**Tell a change from its end.** A value can pass through many values on the way
to one: an arrow key held down, a label dragged, a button held. Show every value
as it is reached, and report the whole as one change when the gesture ends — the
key let go, the pointer released, focus gone elsewhere while the key was still
down. Typing ends as it is committed. A gesture that leaves the value where it
found it is no change, and one that is taken back — Escape during a drag — puts
the first value back and reports nothing. An application then has one entry to
undo for each thing people did.

**Step from outside as the keys step.** A drag or a button that changes the
value makes the field's own steps: from what is typed, when it reads as a value;
on the same multiples; not at all in a field that cannot be changed.

**Step the part the caret is in.** Where a value is shown in parts — the day,
month and year of a date — the arrows change the part the caret is in and leave
that part selected, so the next press continues and typing replaces it. With a
part selected, Left and Right Arrow move from part to part. A caret at the very
end of the text is in no part: that is where a press beside the text puts it.

**Start stepping where the type starts.** An empty field's first step is to the
type's own starting point — today, zero, the nearest end of a range — and not a
step beyond it.

**Leave the command key's arrows to the text.** With Command or Control, the
arrows move the caret to the start and end, as in any field.

**Do not step what cannot be changed.** A read-only or disabled field shows its
value and does not answer the arrows.

**Select on a press where typing should replace.** Where a value is shown with
its unit, a press that brings focus selects the whole text, as Tab does, so that
typing replaces it rather than landing inside it. A second press places the
caret.

**Submit what was typed.** In a form, Return commits the field and then submits
the form — with the value just read, as a number or a date in the form machines
share rather than the text shown. If the text cannot be read, the form is not
submitted. Resetting the form shows the field as it began.

**Replace unread text when the value is replaced.** Text that could not be read
stays until it is dealt with — unless, with focus elsewhere, the value is
changed from outside: it is another value's field now.

**Show a changed value, but not over an edit.** When the value changes from
outside, show it — unless the field is being edited, in which case what is being
typed stays until it is committed or abandoned.

## Platform considerations

**Touch.** Offer the keyboard that suits the type, and make the field at least 44
CSS pixels tall.

**Assistive technology.** State when a field is invalid, and associate the reason
with it.

See also [Numbers](https://ui.publictheta.com/foundations/number-type.md), [Dates](https://ui.publictheta.com/foundations/date-type.md) and
[Scrubbing](https://ui.publictheta.com/foundations/scrub.md).

## Behaviour

Each statement is verified by a test in Chromium, Chromium (touch), Firefox, WebKit, WebKit (touch), unless it names the environments it applies to or is marked open.

### Committing

- What is typed is left as typed, and the value unchanged, until it is committed.
- Enter commits: the text is read as a value and shown in the type's form.
- Leaving the field commits.
- Text that is not a value stays as typed, with the reason, and the value is unchanged.
- Correcting the text and committing again clears the problem.
- An emptied field commits no value, unless a value is required.

### Leaving

- Leaving for another window is not leaving the field: nothing is committed.
- Text that arrives without focus, as a browser fills a field in, is committed as it arrives.
- Text that is the value as shown is not read again.

### In a form

- Enter commits, then submits the form with the value just typed.
- Enter on text that is not a value does not submit the form.
- Resetting the form shows the field as it began.

### Abandoning

- Escape abandons the edit and shows the last value again.
- Escape reaches what contains the field only when there is no edit to abandon.

### Input methods

- A key that belongs to a composition does not commit.
- Text being composed is neither read nor replaced. *(Chromium, Chromium (touch))*

### Stepping

- An arrow steps the part of the value the caret is in, and leaves that part selected.
- With the whole value selected, an arrow makes the type's ordinary step.
- Shift makes a large step, and the Page keys a page.
- Stepping starts from what is typed, when it reads as a value.
- An empty field's first step is to where the type starts.
- With a part selected, the arrows to either side select the part on that side.
- A caret at the very end of the text is in no part.
- With the command key, the arrows are left to the text.
- A field that is read-only is not stepped.
- A type that does not step leaves the arrow keys to the text.

### A change and its end

- What is typed is one change, which ends as it is committed.
- A commit that leaves the value as it was, or that cannot be read, ends nothing.
- A key held down changes the value at every repeat, and the change ends once, when the key is let go.
- Steps that bring the value back to where it was end nothing.
- Leaving the field while a key is held ends the change there.

## Reference implementation

React: `npx shadcn@latest add https://ui.publictheta.com/r/use-field.json`
