| name | touch-pointer |
| description | Load this skill whenever the project contains interactive UI elements that users touch, tap, click, drag, swipe, or gesture with — buttons, links, drag-and-drop interfaces, sliders, carousels, or custom touch interactions. Under no circumstances create touch targets smaller than 44×44 CSS pixels. Absolutely always provide pointer cancellation, single-pointer alternatives to gestures, and load alongside keyboard/SKILL.md since pointer and keyboard requirements are complementary.
|
Touch and Pointer Accessibility Skill
Canonical source: examples/TOUCH_POINTER_ACCESSIBILITY_BEST_PRACTICES.md in mgifford/ACCESSIBILITY.md
This skill is derived from that file. When in doubt, the example is authoritative.
Apply these rules when implementing any interactive UI that users touch, click,
tap, drag, or gesture with.
Load alongside keyboard/SKILL.md — pointer and keyboard requirements are complementary.
Core Mandate
WCAG 2.5.x criteria (introduced in WCAG 2.1 and extended in 2.2) address pointer,
touch, and motion-based interaction. These criteria exist because:
- Motor disabilities affect both keyboard use and pointer/touch precision
- Touch screens have different interaction affordances than mouse
- Many users alternate between keyboard and touch (tablets, convertibles)
- Voice control users activate elements by speaking visible labels — these must match
The full WCAG 2.5 set is listed in the criteria table. This skill covers the
most implementation-relevant patterns.
Severity Scale (this skill)
| Level | Meaning |
|---|
| Critical | Functionality only available via multi-point gesture with no single-pointer alternative; user-scalable=no prevents zoom |
| Serious | Drag-to-reorder with no keyboard/single-pointer alternative; touch target under 24×24px for primary actions |
| Moderate | Mousedown/touchdown action with no up-event cancellation; motion gesture without UI alternative |
| Minor | Target under 44×44px for non-primary actions; spacing between targets too small |
Assistive Technology Context
| AT | How pointer/touch requirements apply |
|---|
| NVDA / JAWS | Primarily keyboard users — see keyboard/SKILL.md. Pointer events don't affect screen reader operation directly |
| VoiceOver (iOS) | Touch-based AT; uses tap, double-tap, swipe — standard HTML interactive elements work natively |
| TalkBack (Android) | Touch-based AT; double-tap to activate; swipe to navigate |
| Voice Control (iOS/macOS) | Activates elements by speaking visible labels; target size matters less than label accuracy |
| Dragon NaturallySpeaking | Click by number or by name; label accuracy critical |
| Switch access | Scans interactive elements; target size and order matter |
| Screen magnification | Small targets are harder to hit at high zoom; spacing prevents mis-taps |
| Stylus / eye gaze | Precision varies; larger targets with more spacing reduce error rate |
Critical: Never Block Zoom (user-scalable=no)
Blocking browser zoom is Critical — it prevents low-vision users from
enlarging content to a usable size.
<meta name="viewport" content="width=device-width, initial-scale=1,
maximum-scale=1, user-scalable=no">
<meta name="viewport" content="width=device-width, initial-scale=1">
Some libraries and frameworks add user-scalable=no automatically (Bootstrap
historically did this in mobile CSS). Audit your viewport meta tag on every
project.
Critical: Single-Pointer Alternatives for Multi-Point Gestures (WCAG 2.5.1)
Any functionality that uses multi-point gestures (pinch-to-zoom, two-finger
rotate, three-finger swipe) must also be available via a single-pointer
interaction.
<div role="group" aria-label="Map controls">
<button type="button" aria-label="Zoom in">+</button>
<button type="button" aria-label="Zoom out">−</button>
</div>
Path-based gestures (swipe, draw) must also have a single-tap or button
alternative. Examples:
- Swipe-to-delete: also provide a delete button
- Swipe-to-reveal: also provide a menu or button
- Draw to sign: also accept typed name as an alternative where legally permitted
Critical: Drag with No Alternative (WCAG 2.5.7 — WCAG 2.2)
Drag-and-drop interfaces must provide a single-pointer (click/tap) or keyboard
alternative. Drag with no alternative is Serious to Critical.
<ul id="priority-list">
<li>
<span class="drag-handle" aria-hidden="true">⠿</span>
Task A
<button type="button" aria-label="Move Task A up">↑</button>
<button type="button" aria-label="Move Task A down">↓</button>
</li>
</ul>
The alternative does not need to look like the drag — it just needs to
provide the same result (reordering, moving between columns, etc.).
Serious: Target Size Minimum (WCAG 2.5.8 — WCAG 2.2)
Interactive targets must be at least 24×24 CSS pixels (AA requirement).
Below 24×24 is Serious. The recommended size for primary actions is 44×44px.
button, a, [role="button"], input[type="checkbox"], input[type="radio"] {
min-width: 24px;
min-height: 24px;
}
.primary-action {
min-width: 44px;
min-height: 44px;
}
When a target is smaller than 44×44px, ensure its offset (the spacing
around it) makes up the difference — a 20×20px icon button with 12px padding
on all sides meets the 44×44 guideline.
.icon-btn {
width: 20px;
height: 20px;
padding: 12px;
}
For inline text links, target size exceptions apply — the WCAG exception
covers inline links in a sentence (where requiring 44px height would break
text flow).
Serious: Pointer Cancellation (WCAG 2.5.2)
Actions triggered on mousedown or touchstart (the "down" event) cannot
be cancelled. Actions must complete on the "up" event (mouseup, touchend,
click) so users can abort by moving the pointer away.
button.addEventListener('mousedown', () => deleteItem());
button.addEventListener('click', () => deleteItem());
For drag operations, completion on drop (the up-event equivalent) is correct.
Custom gesture libraries should use up-events for final action.
Serious: Motion Actuation Alternative (WCAG 2.5.4)
Functionality activated by device motion (shake, tilt) must have a UI alternative.
Users must also be able to disable the motion trigger to prevent accidental activation.
if (window.DeviceMotionEvent) {
window.addEventListener('devicemotion', handleShake);
}
document.getElementById('undo-btn').addEventListener('click', undoLastAction);
document.getElementById('disable-motion').addEventListener('change', (e) => {
if (e.target.checked) {
window.removeEventListener('devicemotion', handleShake);
}
});
Moderate: Adaptive Target Sizing with CSS Media Queries
Use pointer media query to provide larger targets on coarse-pointer (touch)
devices and tighter targets on fine-pointer (mouse) devices:
.nav-item a {
padding: 4px 8px;
}
@media (pointer: coarse) {
.nav-item a {
padding: 12px 16px;
min-height: 44px;
display: flex;
align-items: center;
}
}
@media (pointer: coarse) targets touch screens and styluses.
@media (pointer: fine) targets mouse and trackpad.
@media (any-pointer: coarse) also matches when a coarse pointer is available
(e.g., a laptop with a touchscreen) — use when you want to offer touch-friendly
sizing even on hybrid devices.
Moderate: Touch Target Spacing
Adjacent small targets need spacing to prevent mis-taps — particularly
important for users with tremor, motor difficulties, or at high magnification.
.toolbar button + button {
margin-left: 8px;
}
.option-group label {
display: block;
padding: 8px 0;
}
WCAG 2.5.8 allows targets smaller than 24×24px if the offset (spacing to
adjacent targets) ensures the total space per target is at least 24×24px.
Moderate: Touch-Specific Interaction Patterns
Swipe carousels: must have prev/next button alternatives; auto-advancing
must pause on focus/hover/touch; prefers-reduced-motion must disable animation.
Pull-to-refresh: must have a button alternative; must not be the only
way to refresh content.
Long-press context menus: must have a right-click or button alternative
for desktop users; must not be the only way to access important actions.
Custom touch gestures (swipe, pinch in a non-map context): document them
clearly; always provide single-pointer alternatives.
Moderate: Label in Name for Voice Control (WCAG 2.5.3)
Voice Control users (Dragon NaturallySpeaking, iOS Voice Control) activate
elements by speaking their visible label. The accessible name must contain
the visible text.
<button aria-label="Submit application">Send</button>
<button aria-label="Send application form">Send</button>
<button>Send</button>
The accessible name must begin with or contain the visible text string.
Adding context before or after is fine: "Send application" ✓, "Submit" when
visible text is "Send" ✗.
Minor: touch-action CSS Property
Explicitly declare touch-action on elements that handle their own touch
events to prevent browser interference:
.carousel { touch-action: pan-y; }
.draggable { touch-action: none; }
button { touch-action: auto; }
Overusing touch-action: none can block scrolling on touch devices — only
use it on elements that genuinely handle their own touch events.
Definition of Done Checklist
Key WCAG Criteria
- 1.4.4 Resize Text (AA) — Critical if zoom blocked
- 2.5.1 Pointer Gestures (A) — Serious if multi-point gesture has no alternative
- 2.5.2 Pointer Cancellation (A) — Serious if actions fire on down-event
- 2.5.3 Label in Name (A) — Serious for voice control users
- 2.5.4 Motion Actuation (A)
- 2.5.7 Dragging Movements (AA, WCAG 2.2) — Serious if drag has no alternative
- 2.5.8 Target Size Minimum (AA, WCAG 2.2) — Serious below 24×24px
References
Standards horizon: WCAG 2.5.x criteria are recent additions (2.1 and 2.2).
WCAG 3.0 is expected to extend pointer and touch requirements further.
Monitor: https://www.w3.org/TR/wcag-3.0/