Swimm
Designing complex drag & drop
Simple gesture. Complicated state machine.
Drag and drop looks simple when everything being moved behaves the same way. Swimm's content didn't.
Documents could exist locally, remotely or through Git-backed data. Users could select multiple entities at once, including files and folders with different states and constraints.
The interaction needed to stay predictable even when the underlying operation wasn't.

01Model
Model
One gesture the user performs. Seven states the interface has to hold.
Interaction model
- 01Selectone item, or many
- 02Draggesture begins
- 03Validate targetcan this accept this selection?
- 04Preview resultshow the outcome before committing
- 05Dropgesture ends
- 06Async operationGit, cloud and local state resolve
Success
Failure
Recovery
recovery is a state, not an error message
02Edge cases
Edge cases
Most of the design work lived here. Each of these changes what should be draggable, what reads as a valid target, and what the interface promises while the operation is still resolving.
- 01
Multiple selection
Moving several items together, where the items do not agree with each other.
- 02
Nested folders
Preventing moves that would place a folder inside its own descendant.
- 03
Local documents
Entities whose state has not yet been reflected remotely.
- 04
Mixed entity types
Folders, files and documents that each behave differently on drop.
- 05
Invalid destinations
Communicating that a target cannot accept this particular selection.
- 06
Failed operations
Git and backend failures resolving without leaving the UI inconsistent.
- 07
Large datasets
Keeping the gesture responsive across very large collections.
- 08
Async state
Predictable feedback for the whole window in which nothing is settled.
03Decisions
The interaction model was part of the architecture.
Many edge cases couldn't be solved after implementation with another error message. They affected what should be draggable, what should appear as a valid target, what feedback appears while dragging, and what happens when only part of an operation is valid.
I defined the interaction model alongside the frontend architecture so the behavior remained understandable across these states.

04State map
State map
Validity was never a single boolean. A target could accept part of a selection, or accept it only once an asynchronous check resolved — and the interface had to stay honest about which of those it was.
Interaction model
Target check
per target, per selection
Valid
Invalid
Conditional
Conditional targets
Async validation
Success / rollback
never a half-applied move
Selection dimension
- single
- multiple
- mixed
- nested
- local
- remote
every target check runs against whichever combination is in hand
05Outcome
Outcome
The resulting interaction allowed users to manipulate complex content using a familiar gesture while keeping the underlying Git, cloud and local-state differences largely out of sight.
Good interaction design isn't always about adding behavior. Sometimes it's deciding which complexity the user never needs to see.