# Features Research: Drag-Drop Editor UX **Domain:** Drag-and-drop itinerary editor for iOS sports travel app **Researched:** 2026-01-18 **Confidence:** HIGH (multiple authoritative sources cross-verified) ## Executive Summary Polished drag-drop requires deliberate visual feedback at every state transition. The difference between "feels broken" and "feels delightful" comes down to: lift animation, predictable insertion indicators, smooth reshuffling, and magnetic snap-to-place. Your constraints (fixed day headers, fixed games, movable travel/custom items) add complexity but are achievable with proper drop zone logic. --- ## Table Stakes Features users expect. Missing any of these makes the editor feel broken. | Feature | Why Expected | Complexity | Implementation Notes | |---------|--------------|------------|---------------------| | **Lift animation on grab** | Users expect physical metaphor - picking up an object | Low | Elevation (shadow), scale 1.02-1.05x, slight z-offset | | **Ghost/placeholder at origin** | Shows where item came from, reduces anxiety | Low | Semi-transparent copy or outlined placeholder in original position | | **Insertion indicator line** | Must show exactly where item will drop | Medium | Horizontal line with small terminal bleeds, appears between items | | **Items move out of the way** | Preview of final state while dragging | Medium | ~100ms animation, triggered when dragged item center overlaps edge | | **Magnetic snap on drop** | Satisfying completion, confirms action worked | Low | 100ms ease-out animation to final position | | **Clear invalid drop feedback** | Don't leave user guessing why drop failed | Low | Item animates back to origin if dropped in invalid zone | | **Touch hold delay (300-500ms)** | Distinguish tap from drag intent | Low | iOS standard; prevents accidental drags | | **Haptic on grab** | Tactile confirmation drag started | Low | UIImpactFeedbackGenerator.light on pickup | | **Haptic on drop** | Tactile confirmation action completed | Low | UIImpactFeedbackGenerator.medium on successful drop | | **Scroll when dragging to edge** | Lists longer than viewport need auto-scroll | Medium | Scroll speed increases closer to edge, ~40px threshold | ### Insertion Indicator Details The insertion line is critical. Best practices: - Appears **between** items (in the gap), not on top - Has small terminal bleeds (~4px) extending past item edges - Triggered when center of dragged item crosses edge of potential neighbor - Color should contrast clearly (system accent or distinct color) ### Animation Timing | Event | Duration | Easing | |-------|----------|--------| | Lift (pickup) | 150ms | ease-out | | Items shuffling | 100ms | ease-out | | Snap to place (drop) | 100ms | ease-out | | Return to origin (cancel) | 200ms | ease-in-out | --- ## Nice-to-Have Polish features that delight but aren't expected. | Feature | Value | Complexity | Notes | |---------|-------|------------|-------| | **Slight tilt on drag (2-3 degrees)** | Trello's signature polish; makes interaction feel playful | Low | Rotate3D effect, matches brand personality | | **Progressive drop zone highlighting** | Visual intensifies as item approaches valid zone | Medium | Background color change, border enhancement | | **Multi-item drag with count badge** | Power users moving multiple items at once | High | Not needed for v1; itinerary items are usually moved one at a time | | **Keyboard reordering (a11y)** | Up/Down arrows via rotor actions | Medium | Important for accessibility; add accessibilityActions | | **Undo after drop** | Recover from mistakes | Medium | Toast with "Undo" button, ~5 second timeout | | **Drag handle icon** | Visual affordance for draggability | Low | 6-dot grip icon (Notion-style) or horizontal lines | | **Cancel drag with escape/shake** | Quick abort | Low | Shake-to-cancel on iOS; return to origin | | **Drop zone "ready" state** | Zone visually activates before item enters | Low | Subtle background shift when drag starts | ### Tilt Animation (Trello-style) The 2-3 degree tilt on dragged items is considered "gold standard" polish: - Adds personality without being distracting - Reinforces physical metaphor (picking up a card) - Should match your app's design language (may be too playful for some apps) --- ## Overkill Skip these - high complexity, low value for an itinerary editor. | Feature | Why Skip | What to Do Instead | |---------|----------|-------------------| | **Drag between sections/screens** | Your items live within days; cross-day moves are rare | Allow within same list only, or use "Move to..." action menu | | **Nested drag-drop** | Games within days is hierarchy enough | Keep flat list per day section | | **Free-form canvas positioning** | Not applicable to linear itinerary | Stick to list reordering | | **Real-time collaborative drag** | Massive sync complexity | Single-user editing | | **Drag-to-resize** | Items don't have variable size | Fixed item heights | | **Custom drag preview images** | Native preview is sufficient | Use default lifted appearance | | **Physics-based spring animations** | Overkill for list reordering | Simple ease-out is fine | --- ## Interactions to Support Specific drag scenarios for your itinerary context. ### Scenario 1: Move Custom Item Within Same Day **User intent:** Reorder "Dinner at Lou Malnati's" from after to before the Cubs game **Expected behavior:** 1. Long-press on custom item (300ms) - haptic feedback 2. Item lifts (shadow + scale), ghost remains at origin 3. Drag within day section - insertion line appears between valid positions 4. Games and travel segments shuffle with 100ms animation 5. Drop - item snaps into place, haptic confirms **Constraints:** - Custom item can move anywhere within the day - Cannot move before/after day header - Cannot replace or overlay a game (games are fixed) ### Scenario 2: Move Custom Item to Different Day **User intent:** Move hotel check-in from Day 2 to Day 1 **Expected behavior:** 1. Long-press and lift 2. Drag toward Day 1 section 3. Auto-scroll if Day 1 is off-screen 4. Insertion line appears at valid positions in Day 1 5. Day 2 collapses to show item removed; Day 1 expands 6. Drop - item now in Day 1 **Constraints:** - Can cross day boundaries - Still cannot land on games ### Scenario 3: Move Travel Segment (Constrained) **User intent:** Move "Drive: Chicago to Milwaukee" earlier in the day **Expected behavior:** 1. Long-press on travel segment 2. Item lifts (possibly with different visual treatment since it's constrained) 3. Insertion line only appears at **valid** positions (before/after games it connects) 4. Invalid positions show no insertion line (or dimmed indicator) 5. If dropped at invalid position, item animates back to origin **Constraints:** - Travel segments connect stadiums/locations - Can only move within logical route order - Must validate position before showing insertion indicator ### Scenario 4: Attempt to Move Fixed Item (Game) **User intent:** User tries to drag a game (not allowed) **Expected behavior:** 1. Long-press on game item 2. **No lift animation** - item doesn't respond as draggable 3. Optionally: subtle shake or tooltip "Games cannot be reordered" 4. User understands this item is fixed **Visual differentiation:** - Fixed items should NOT have drag handles - Could have different visual treatment (no grip icon, different background) ### Scenario 5: Drag to Invalid Zone **User intent:** User drags custom item but releases over a game **Expected behavior:** 1. Item is being dragged 2. Hovers over game - no insertion line appears (invalid) 3. User releases 4. Item animates back to origin (~200ms) 5. Optional: brief error state or haptic warning --- ## Visual States Summary | Element State | Visual Treatment | |--------------|------------------| | **Resting (draggable)** | Normal appearance, optional drag handle icon on hover/focus | | **Resting (fixed)** | Normal, but NO drag handle; visually distinct | | **Lifted/grabbed** | Elevated (shadow), slight scale up (1.02-1.05), optional tilt | | **Ghost at origin** | Semi-transparent (30-50% opacity) or outlined placeholder | | **Insertion line** | Accent-colored horizontal line, ~2px height, bleeds past edges | | **Invalid drop zone** | No insertion line; item over zone dims or shows warning | | **Drop zone ready** | Subtle background color shift when any drag starts | | **Dropped/success** | Snaps to place, haptic feedback, ghost disappears | | **Cancelled/error** | Returns to origin with animation, optional warning haptic | --- ## Accessibility Requirements | Requirement | Implementation | Priority | |-------------|----------------|----------| | **VoiceOver reordering** | accessibilityActions with "Move Up" / "Move Down" | High | | **Rotor integration** | Actions appear in VoiceOver rotor | High | | **Focus management** | Focus follows moved item after reorder | Medium | | **Live region announcements** | Announce position change ("Item moved to position 3") | Medium | | **Fallback buttons** | Optional up/down arrows as visual alternative | Low (nice to have) | SwiftUI example for accessibility: ```swift .accessibilityAction(named: "Move Up") { moveItemUp(item) } .accessibilityAction(named: "Move Down") { moveItemDown(item) } ``` --- ## Mobile-Specific Considerations | Concern | Solution | |---------|----------| | **Fat finger problem** | Minimum 44x44pt touch targets; drag handles at least 44pt wide | | **Scroll vs. drag conflict** | Long-press delay (300-500ms) distinguishes intent | | **Viewport limitations** | Auto-scroll at edges (40px threshold), speed increases near edge | | **One-handed use** | Consider "Move to..." button as alternative to long-distance drags | | **Accidental drops** | Generous drop zones; magnetic snap; undo option | --- ## Anti-Patterns to Avoid | Anti-Pattern | Why Bad | Do Instead | |--------------|---------|------------| | **Edge-to-edge shuffle trigger** | Feels "twitchy", items move unexpectedly | Use center-overlap-edge trigger | | **Instant reshuffle (no animation)** | Disorienting, hard to track what moved | 100ms animated transitions | | **No ghost/placeholder** | User loses context of original position | Always show origin indicator | | **Drag handle too small** | Frustrating on touch | Minimum 44pt, ideally larger | | **Remove item during drag** | Anxiety - "where did it go?" | Keep ghost visible at origin | | **Scroll too fast at edges** | Overshoots, loses control | Gradual speed increase | | **No invalid feedback** | User thinks interaction is broken | Clear visual/haptic for invalid drops | --- ## Sources **High Confidence (verified with multiple authoritative sources):** - [Smart Interface Design Patterns - Drag and Drop UX](https://smart-interface-design-patterns.com/articles/drag-and-drop-ux/) - [Atlassian Pragmatic Drag and Drop Design Guidelines](https://atlassian.design/components/pragmatic-drag-and-drop/design-guidelines/) - [Pencil & Paper - Drag & Drop UX Design Best Practices](https://www.pencilandpaper.io/articles/ux-pattern-drag-and-drop) - [Nielsen Norman Group - Drag and Drop: How to Design for Ease of Use](https://www.nngroup.com/articles/drag-drop/) **Medium Confidence (single authoritative source):** - [LogRocket - Designing Drag and Drop UIs](https://blog.logrocket.com/ux-design/drag-and-drop-ui-examples/) - [Darin Senneff - Designing a Reorderable List Component](https://www.darins.page/articles/designing-a-reorderable-list-component) - [Apple Human Interface Guidelines - Drag and Drop](https://developer.apple.com/design/human-interface-guidelines/drag-and-drop) **Low Confidence (community patterns):** - Various SwiftUI implementation guides (verify APIs against current documentation) - Trello UX patterns referenced in multiple articles (de facto standard)