# Undo and redo

> Taking back what was done and doing it again: one line of history, an action at a time.

Undo takes back what was just done; redo does it again. Together they make an
interface safe to try things in: nothing done by a slip of the hand has to stay
done.

## Best practices

**Undo an action, not a keystroke.** One undo takes back everything one action
did — a whole paste, a whole clearing, every cell a fill reached — however many
values it changed. A run of small changes that people think of as one, such as
the characters of a word or the steps of a drag, is one action too.

**Keep one line of history.** Doing something new after undoing discards what
was undone. Redo repeats only what undo has just taken back.

**Show what changed.** After an undo or a redo, bring what it changed into view
and select it, and say that it happened to people who cannot see it happen.

**Undo only what is still there.** When the data is replaced from elsewhere —
other records are loaded, a collaborator's version arrives — changes made to
what was there before no longer apply, and are forgotten rather than undone into
something else.

**Leave a field's own undo to the field.** While text is being typed in a
field, undo takes back the typing, as it does in any field. The wider history
begins where the field is committed.

**Keep enough, not everything.** Hold a generous number of actions and let the
oldest go.

## Conventions

| Intent | Keyboard                               |
| ------ | -------------------------------------- |
| Undo   | Command-Z                              |
| Redo   | Command-Shift-Z, and Command-Y as well |

Command is ⌘ on Apple platforms and Ctrl elsewhere.

## 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.

### Undoing and redoing

- Undo returns what was done, last first; redo returns it again, in the order it was done.
- With nothing to undo, or to redo, there is nothing returned.
- Doing something new after undoing discards what was undone.
- It behaves as a plain list of what was done would, whatever is done to it.

### Limit

- Past its limit, the oldest entry is forgotten and the rest are kept.
- A history that keeps nothing is refused.

### Merging

- A change merged into the one before is undone with it, as one.
- A change that does not merge is recorded separately.
- Nothing merges into a change that has been undone, nor into an empty history.

## Reference implementation

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