Swipe Direction Lock

Try to recall the first time you used Tinder. You wanted to swipe left — and the card slid left. Nothing remarkable. But if you stop and think about it, you’ll realize it isn’t simple at all.

A finger never travels straight. When you swipe left, your finger also drifts a few pixels up, a few pixels down. If the screen reacted to every one of those tiny movements, the card would slide sideways while jerking up and down with every millimetre your finger strays. But you don’t see that. Because Tinder — and most apps that do gestures well — quietly solved this problem.

Drag the card sideways or up — try dragging diagonally and watch the system pick a direction

Not started
3
2
1 ← drag → or ↑
Horizontal locked
Vertical locked

The pain

Imagine a screen with two kinds of gesture: swipe horizontally to switch tabs, swipe vertically to scroll the content. This is an extremely common pattern — Instagram, TikTok, and Apple Music all use it. And when done right, it feels unbelievably smooth.

But when done wrong, it’s one of the worst experiences on mobile. You want to scroll down to keep reading, but the screen switches tabs instead. Or you want to switch tabs, but the content scrolls. You have no control, even though your finger is clearly doing exactly what you intended.

That feeling — when the interface doesn’t understand your intent — is one of the biggest sources of friction in mobile UX. Users don’t articulate it. They just feel the app is “hard to use” without knowing why.

The designer’s insight

When Apple’s UX team designed scrolling for the first iPhone, they realized something: a human finger is not a mouse. A mouse moves precisely along an axis. A finger doesn’t — every swipe has noise, every swipe has drift.

The solution was not to ask users to swipe more precisely. The solution was to let the system read intent on its own.

That insight led to direction lock: for a short window after the finger touches the screen and starts moving, the system observes — is there more horizontal or more vertical movement? Once it’s clear enough, the system commits to one axis and blocks the other entirely. From then on, every movement of the finger produces only one kind of action, with no cross-contamination.

This explains why scrolling on iOS never accidentally switches tabs, and switching tabs never accidentally scrolls. No matter how much your finger drifts within the first 8px — the system has already decided, and it will hold that decision until the end of the gesture.

The uncommitted zone — the moment the system listens

The first 8px is a zone of silence. The element doesn’t move. The system does nothing — it just listens.

The interesting thing is that users don’t notice this window exists. At normal finger speed, 8px lasts about 40–60ms — shorter than the threshold of conscious human perception. But raise it to 20px or more and users start to feel lag. The interface seems “slow to respond.”

0px  → 8px   : silence, observe
8px  → 9px   : commit direction, begin moving
9px  → ...   : follow the chosen axis, block the other

The number 8px is not a hard rule — iOS uses about 10px, Android ranges from 8–12px depending on the OEM — but they all fall within a narrow band. Smaller, and it commits wrongly before the finger has settled on a direction. Larger, and the user feels ignored.

The real difficulty: the moment of commit

Direction lock isn’t hard. The hard part is making the moment of commit look natural.

The instant the system determines a direction, it starts moving the element. But if you measure displacement from the original touchstart point, the element will “catch up” to the finger — jumping from position 0 to the finger’s current position — in a single frame. That jump is perceptible, especially when the finger moves quickly.

The solution most platform implementations use: reset the measurement origin to the finger’s actual position at the moment of commit. The element starts moving from 0, not from its earlier position. The result: no jump, no catch-up. Just natural movement from where the user currently is.

This is something hard to see when it’s right — but extremely irritating when it’s wrong.

Spring-back and the feeling of physicality

When a user drags a card and then releases without going far enough to trigger the action, what happens?

Most beginners let the element snap back to its old position instantly — or use ease-out. Both look mechanical. Nothing in the physical world moves like that.

Platforms that do gestures well use a spring with a touch of overshoot — the element flies slightly past its origin, then bounces back. That bounce isn’t large, isn’t obvious. But it’s enough for the human brain to register “this is an object with mass, not a pixel.” That feeling builds trust in the interface.

This is why the iOS springboard, Android sheets, and every good bottom drawer have a slight bounce when they snap back — even if no one says so out loud.

Dismiss by intent, not by measurement

A smaller issue, but enough to ruin the experience: what is the condition for dismissing a gesture?

The intuitive answer is distance — drag far enough and it dismisses. But users sometimes flick quickly and briefly — the finger hasn’t traveled far enough, yet the intent is clearly to dismiss. If the system only measures distance, that flick gets rejected. The interface looks laggy, even though the finger did the right thing.

The solution: dismiss when far enough OR fast enough. Those two conditions represent two ways users express the same intent — a slow long drag, or a quick short flick. The system should understand both.

This is the kind of decision a designer can’t find from code or documentation. You have to use the app, test it by hand, notice what looks “natural” and what looks “stiff” — and only then understand why.

See also: Gesture Feedback Motion, Spring Parameters, Modal & Sheet Animation.