Make the Layer Between Intent and Software Thin
Every interface sits between what someone wants and what the software does. The goal is to make that layer as thin as possible. Interfaces people call "magical" are usually not doing anything clever visually; they inferred what the user was about to do and skipped a step.
Ask of any flow: what does the user obviously want here, and what are we making them spell out anyway?
- Count the steps between arriving and getting the result
- Any step where the answer is already knowable from context is a candidate to remove
- Inference is most valuable at the most tedious point in the flow, not the easiest one
Bad inference is worse than none. Only infer when you would be right nearly every time, and always leave the manual path intact.
Infer From the Clipboard
Pasting is a strong statement of intent. If the shape of the pasted content tells you what the user meant, act on it instead of forcing the content into one field.
The canonical case is a form with repeated rows, like key and value pairs. Someone with a file of ten variables does not want to fill ten pairs of fields by hand. They want to paste the file.
function onPaste(event: React.ClipboardEvent) {
const text = event.clipboardData.getData("text");
const lines = text.split("\n").filter(Boolean);
// One line is a normal paste. Many lines is an intent to bulk fill.
if (lines.length < 2) return;
event.preventDefault();
setRows(lines.map(parseRow));
}
Other shapes worth detecting on paste:
- A URL pasted into a text field, when the field accepts a link
- Comma or tab separated values pasted into a single row of a table
- An image on the clipboard pasted into a field that accepts an upload
- A phone number or card number with the user's own spacing, which you reformat rather than reject
Never block paste to enforce formatting. Accept whatever arrives and normalise it yourself.
Infer From Context You Already Have
Before adding an input, check whether the answer is already on hand. The active tab, the current selection, the last thing the user opened, the time of day, and the device are all free context.
Examples of the pattern:
- A save action reads the title, URL, and icon from the active page instead of asking for them
- A share sheet ranks recent and frequent recipients ahead of an alphabetical list
- A new record inherits the project or folder the user is currently viewing
- A date field defaults to the most likely date, not to empty
The test is whether the user would have typed exactly what you inferred. If yes, prefill it and let them edit. If it is a guess, leave it blank rather than making them undo your guess.
Treat Speed as a Signal
How fast someone moves is intent data. A slow, deliberate drag near a boundary usually means they are trying to align to it. A fast one usually means they are trying to get past it.
Applying resistance at low speed and none at high speed lets one gesture serve both goals without a mode switch.
// Near an edge, resist slow movement and let fast movement through.
const resistance = Math.abs(velocity) < 400 ? 0.35 : 1;
const next = position + delta * resistance;
The same idea drives release behaviour. Use velocity to decide where a flicked element should land, rather than distance alone. See get-ux-principle({ topic: "gestures" }) for the projection formula.
Preserve Small Conveniences
Operating systems have decades of inference in their text handling that people now expect everywhere:
- Cutting a word inside a sentence also cuts one of the surrounding spaces
- Pasting a word next to another word inserts the missing space
- Double clicking selects a word, triple clicking selects the line or paragraph
- Typing over a selection replaces it rather than appending
If you build a custom editor, a token input, or anything that intercepts text entry, you are on the hook for these. Users will not report them as bugs. They will just find your input annoying.
When Not to Infer
Inference is a shortcut, so the cost of getting it wrong scales with how hard it is to undo.
- Do not infer destructive or irreversible actions
- Do not infer anything the user cannot see and correct before it takes effect
- Do not infer from data the user did not knowingly give you
- Do not remove the manual path once the inferred path exists
If an inference misfires, recovery must be a single obvious action.
Checklist
- The most tedious step in the flow has been examined for something inferable
- Multi line paste is handled where a form has repeating rows
- Paste is never blocked to enforce formatting
- Fields that can be prefilled from context are prefilled, not left empty
- Guesses are left blank rather than filled with a likely wrong value
- Inferred values remain editable
- Movement speed is used where a gesture serves both precision and escape
- Standard text editing conveniences survive in custom inputs
- Nothing destructive or irreversible is triggered by inference
- The manual path still exists alongside every shortcut