# Dragging

> Press, move, release: telling a drag from a click, following the pointer, and letting people cancel.

Dragging is how people move things with their hands: a thing on a canvas, the
edge of a column, a marquee, the view itself. Every drag is the same gesture —
press, move, release — and every one has to tell a drag from a click, follow the
pointer wherever it goes, and let people change their mind.

## Best practices

**Let a click stay a click.** A press becomes a drag only after it has
travelled a little way. A hand is not perfectly still when it presses; without
this, every click would nudge what it clicked.

**Fit the distance to the pointer.** A mouse can be held to a few pixels; a pen
slips a little as it lands; a fingertip covers many pixels and rolls as it
presses. Wait for about 3 pixels from a mouse, 6 from a pen and 10 from a
finger. Measure in a straight line from the press, so that a diagonal drag
begins as soon as a level one.

**Follow the pointer everywhere.** Once a drag has begun it continues wherever
the pointer goes — over other things, out of the area it began in — and ends
where the pointer is released.

**Measure from the press.** Work out what a drag has done from how far the
pointer is from where it was pressed, not from the last step it took. Steps
accumulate error; a distance does not, and it lets a drag be put back exactly.

**Read the modifier keys as they are now.** A key held changes what a drag
means — constrain, copy, move freely — and people press and release such keys in
the middle of a drag. Apply the change at once, even while the pointer rests.

**Always let people cancel.** Escape abandons a drag and puts everything back as
it was. So does anything that takes the pointer away: the system claiming a
touch, a menu opening, the window losing the pointer.

**Keep a cancelled drag from doing anything else.** The Escape that cancels a
drag does not also close the dialog the drag was in. The release that follows a
drag — finished or cancelled — is not a click on what is under it.

**One pointer, one drag.** A second finger or pointer pressed during a drag does
not take it over. The secondary button never begins a drag: it is for a menu.

**Keep the page still.** A drag does not select the text it passes over, start
the browser's own drag of an image or a link, or scroll the page under a
finger. Say which directions, if any, a finger may still scroll in.

**Report a drag as one change.** However many steps it took, a drag is one
action to undo. Show its progress as it goes; record it when it ends.

## Conventions

| Intent             | Pointer                            | Keyboard | Touch             |
| ------------------ | ---------------------------------- | -------- | ----------------- |
| Begin              | Press and move 3 pixels (a pen: 6) | —        | Press and move 10 |
| Cancel             | —                                  | Escape   | —                 |
| Change the meaning | Hold or release a modifier key     | —        | —                 |
| End                | Release                            | —        | Lift              |

Whatever can be dragged can also be done from the keyboard, by other means: a
drag is never the only way.

See also [Snapping](https://ui.publictheta.com/foundations/snap.md), [Resizing](https://ui.publictheta.com/foundations/resize.md) and
[Pan and zoom](https://ui.publictheta.com/foundations/viewport.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.

### Threshold

- A press is a drag only once it has travelled past the threshold, in any direction.
- The threshold is 3 pixels for a mouse, 6 for a pen and 10 for a finger.
- A pointer of an unknown kind is held to the coarsest threshold.
- A press released where it was made is a click, not a drag.
- A press that moves past the threshold becomes a drag, and says where it began.
- A finger must travel farther than a mouse before it drags. *(Chromium (touch))*

### The drag

- Each move reports the whole distance from the press.
- The element captures the pointer once the drag begins, and not before.
- The drag goes on outside the element, and ends where the pointer is released.
- The modifier keys are reported as they are at each move.
- A modifier pressed or released while the pointer rests is reported at once.
- A drag does not end as a click.
- After a drag that no click follows, the next click is still heard.
- Text is not selected by a drag across it.
- The browser's own drag of an image or a link does not start.

### Cancelling

- Escape cancels the drag, which reports no distance: where to put things back.
- The release that follows a cancelled drag is not a click; the next press's is.
- The Escape that cancels a drag is not heard by anything else.
- The system taking the pointer away cancels the drag.
- Losing the capture cancels the drag.
- A context menu cancels the drag.
- A context menu that is refused opens nothing, and cancels nothing.

### Pointers and buttons

- A second pointer does not take over a drag in progress.
- The secondary button never drags.
- The middle button drags only where it is asked to.

## Reference implementation

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