Form controls · Lab

Inline edit — save & cancel

Nine ways an open field can offer commit and abandon. Every specimen is live — edit it, save or cancel, and watch the committed value under the card. Enter saves and Escape cancels in all nine, so the only variable is the visible affordance.

What we're solving

Today's ValueChangeField puts two 40px icon buttons beside a 40px input. In the 22rem record column that pair costs about 88px — a third of the row — and a filled amber checkmark reads as the loudest thing in a panel of quiet data. The candidates below either move the actionsinside the control, under it, or remove them.

Two things worth deciding while comparing: whether the confirm should be afilled affordance or a quiet one, and whether cancel needs to exist at all if Escape and an undo path already do the job.

All nine

01Ghost icons inside
ModelSaf-T-Liner C2

When: The default fix for a narrow panel — the field keeps the full row width and the actions cost nothing.

Seen in: The input-adornment convention: a search field's clear ✕, a password reveal eye. Material UI calls it InputAdornment.

committed: Saf-T-Liner C2

02Brand confirm inside
ModelSaf-T-Liner C2

When: Same as 01, but the commit is consequential enough to want a filled affordance rather than a ghost one.

Seen in: Compose/send fields — a filled primary sitting inside the composer's trailing edge.

committed: Saf-T-Liner C2

03Divided tray inside
ModelSaf-T-Liner C2

When: Longer values, where an undivided icon pair can look like part of the text.

Seen in: Date/number steppers and currency selectors that partition a single control.

committed: Saf-T-Liner C2

04Attached group
ModelSaf-T-Liner C2

When: You want the actions to read as real buttons (bigger hit target than an adornment) without paying for a gap.

Seen in: The classic input-group: Bootstrap's input-group, a search box with an attached Go button.

committed: Saf-T-Liner C2

05Compact icons beside (baseline)
ModelSaf-T-Liner C2

When: The smallest possible change from today: same layout, 32px buttons instead of 40px. Still costs ~72px of row.

Seen in: This is the current ValueChangeField, one size down.

committed: Saf-T-Liner C2

06Buttons below
ModelSaf-T-Liner C2

When: Words beat glyphs — the commit is worth labelling, and the panel has vertical room to spare.

Seen in: GitHub comment editing; Jira and Confluence inline edit both drop a Save/Cancel pair under the field.

committed: Saf-T-Liner C2

07Actions on dirty only
ModelSaf-T-Liner C2

When: Fields opened to read as often as to change. The appearing row doubles as the unsaved-changes cue.

Seen in: Settings panes that reveal a Save bar the moment something changes.

committed: Saf-T-Liner C2

08Commit on blur
ModelSaf-T-Liner C2

When: High-frequency editing where confirmation is friction. Needs an undo path — there is no cancel button to reach for.

Seen in: Notion, Linear, Airtable, Google Sheets — click away and it's saved.

committed: Saf-T-Liner C2

09Keyboard hint only
ModelSaf-T-Liner C2

When: Dense, power-user surfaces. Discoverable only by reading the hint, so it fails a mouse-only audience.

Seen in: Slack's message editor spells out 'escape to cancel · enter to save' beneath the box.

committed: Saf-T-Liner C2

At the real record-column width (22rem)

The cards above are wider than the panel this is for. These three are the in-panel candidates rendered at the actual column width — the size the choice has to survive.

01 · Ghost inside

01Ghost icons inside
ModelSaf-T-Liner C2

When: The default fix for a narrow panel — the field keeps the full row width and the actions cost nothing.

Seen in: The input-adornment convention: a search field's clear ✕, a password reveal eye. Material UI calls it InputAdornment.

committed: Saf-T-Liner C2

04 · Attached group

04Attached group
ModelSaf-T-Liner C2

When: You want the actions to read as real buttons (bigger hit target than an adornment) without paying for a gap.

Seen in: The classic input-group: Bootstrap's input-group, a search box with an attached Go button.

committed: Saf-T-Liner C2

05 · Beside (today)

05Compact icons beside (baseline)
ModelSaf-T-Liner C2

When: The smallest possible change from today: same layout, 32px buttons instead of 40px. Still costs ~72px of row.

Seen in: This is the current ValueChangeField, one size down.

committed: Saf-T-Liner C2

Layout shift — does 01 stay out of the flow?

On its own, no. Specimen 01 fixes the width problem, not the height one. Its resting row is 44px (a label plus a line of text); its editor is 64px (a label plus a 40px control). Opening a field pushes everything below it down 20px. The cards above hide this because their demo area reserves a fixed height.

Two ways to hold the layout still, both live below. Open the top field in each stack and watch the heavy rule near the bottom — in A it drops, in B and C it does not move.

A · As built (01)shifts 20px
ModelSaf-T-Liner C2
Year2020
Mileage70,445 mi

Anything below the rule moves when a field above reflows.

The editor is 20px taller than the row it replaces, so every field beneath it drops. Open the top field and watch the rule.

B · Reserved heightno shift
ModelSaf-T-Liner C2
Year2020
Mileage70,445 mi

Anything below the rule moves when a field above reflows.

The resting value line already stands 40px tall, so the control drops into space that was always there. Costs ~20px of height per field at rest — a airier panel, but nothing ever moves.

C · Out of flowno shift
ModelSaf-T-Liner C2
Year2020
Mileage70,445 mi

Anything below the rule moves when a field above reflows.

The resting row keeps its 44px and turns invisible; the editor paints over it in an absolute layer with a shadow. Read mode stays compact and nothing moves — the trade is that the open editor overlaps the field below, and the shadow makes an in-place edit read like a popover.

D · Seamlessno shift
Model
Year
Mileage

Anything below the rule moves when a field above reflows.

Read and edit are the same 40px box; at rest it is simply undressed. Nothing floats, nothing is positioned, and there is no shift because there was never a swap. This is what Notion, Linear and Airtable do, and what Atlassian's InlineEdit prescribes.