2.5.7 Dragging Movements
Level: AA | Principle: Operable | Since: WCAG 2.2 | Automation: Manual
What This Means
Any functionality that uses dragging (click-and-hold then move) must also be achievable through single-pointer actions without dragging — such as clicking buttons, using menus, or tapping targets. Dragging requires sustained, precise pointer control that many users cannot perform.
Who This Affects
- Motor impairment users — may lack the fine motor control to click, hold, and move simultaneously
- Tremor or spasticity users — dragging requires sustained steady control that tremors disrupt
- Head pointer / eye tracking users — drag gestures are extremely difficult with these input methods
- Touch screen users with limited dexterity — drag-and-drop on mobile is unreliable for many users
Common Pitfalls
1. Drag-and-drop reordering with no alternative
<!-- Bad: only way to reorder is drag-and-drop -->
<ul class="sortable">
<li draggable="true">Item 1</li>
<li draggable="true">Item 2</li>
<li draggable="true">Item 3</li>
</ul>
<!-- No move-up / move-down buttons -->
2. Slider with no text input
<!-- Bad: only way to set value is dragging the thumb -->
<input type="range" min="0" max="100" />
<!-- No number input or step buttons -->
3. Kanban board with drag-only movement
Cards can only be moved between columns by dragging — no menu or button to select a destination column.
4. File upload that only accepts drag-and-drop
<!-- Bad: only drag-and-drop file upload -->
<div class="dropzone" ondrop="handleDrop(e)">
Drag files here
</div>
<!-- No file input or browse button -->
How to Fix
Add move buttons to sortable lists
<ul class="sortable">
<li>
<span>Item 1</span>
<button aria-label="Move Item 1 up" onclick="moveUp(0)">▲</button>
<button aria-label="Move Item 1 down" onclick="moveDown(0)">▼</button>
</li>
<li>
<span>Item 2</span>
<button aria-label="Move Item 2 up" onclick="moveUp(1)">▲</button>
<button aria-label="Move Item 2 down" onclick="moveDown(1)">▼</button>
</li>
</ul>
Add number input alongside range slider
<label for="volume">Volume</label>
<input type="range" id="volume" min="0" max="100" value="50"
oninput="volumeNumber.value = this.value" />
<input type="number" id="volumeNumber" min="0" max="100" value="50"
oninput="volume.value = this.value" />
Add context menu to Kanban cards
<div class="card">
<h3>Task: Fix login bug</h3>
<!-- Drag works for mouse users -->
<!-- Menu alternative for everyone else -->
<select aria-label="Move to column" onchange="moveCard(this.value)">
<option value="todo">To Do</option>
<option value="progress" selected>In Progress</option>
<option value="done">Done</option>
</select>
</div>
Always pair drag-and-drop file upload with a file input
<div class="dropzone" ondrop="handleDrop(e)" ondragover="e.preventDefault()">
<p>Drag files here or</p>
<label for="file-input" class="browse-btn">Browse files</label>
<input type="file" id="file-input" onchange="handleFiles(this.files)" />
</div>
How to Test
- Identify every drag interaction on the page: sortable lists, sliders, file upload drop zones, Kanban boards, color pickers, and map panning.
- For each drag interaction, look for a single-click or keyboard alternative: move up/down buttons for sortable lists, a number input for sliders, a file browse button for upload zones.
- Test each alternative to confirm it achieves the same result as dragging.
- Check that range sliders (
<input type="range">) can be operated with arrow keys and optionally have a paired number input. - Pass: Every drag-based interaction has a single-click or keyboard alternative that achieves the same result.
- Fail: Any functionality requires dragging with no single-pointer or keyboard alternative provided.
axe-core Rules
| Rule | What It Checks | |------|---------------| | — | No automated axe-core rule for this criterion. Drag alternatives require manual review. |