auditmysitev2.0.2

Missing alternative for pointer gestures

manual/pointer-gestures

WCAG success criterion
2.5.1 (level A)
Outcome class
Manual. A tool cannot decide this check. The audit only points a person at it; it is never counted as automatically verified.
Area
Accessibility, Navigation & Operation
Default severity
medium
axe-core rule
pointer-gestures

Why we flag this

Users with motor impairments cannot operate the functionality.

Required touch gestures without a click fallback.

What the rule checks

Scope. Pages with gesture-driven content in the markup: draggable="true", touch/pointer-move/drag handler attributes, or carousel/slider/map library classes (swiper, slick, carousel, leaflet, ...).

Expectation. One needs_review (UNTESTED) note per page, at the root, when the page contains gesture-driven content; never pass or violation. Pages without such content get no note.

Why a person has to decide. Whether every path-based or multipoint gesture also works with a single pointer is only shown by operating the widget; the markup shows at most that gestures exist.

Source. WCAG 2.2 SC 2.5.1 Pointer Gestures

Detection: shared; needs dom.

Failing example

The check flags this for review. Corpus case interaction_manual_checklist. The page may contain further findings for other rules.

interaction_manual_checklist.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Member area</title>
    <style>
        body { font-family: sans-serif; margin: 0; padding: 16px; color: #111; background: #fff; }
        a, button, input { display: inline-block; min-width: 44px; min-height: 44px; padding: 12px; box-sizing: border-box; margin: 4px; }
        .skip { position: absolute; left: -9999px; }
        .skip:focus { left: 16px; }
    </style>
</head>
<body>
    <a class="skip" href="#main">Skip to main content</a>
    <header><p>Example Club</p></header>
    <nav aria-label="Main">
        <a href="/" aria-current="page">Home</a>
        <a href="/events">Events</a>
    </nav>
    <main id="main">
        <h1>Member area</h1>

        <!-- manual/pointer-gestures: a swipe carousel -->
        <section aria-label="Photo gallery">
            <h2>Last season</h2>
            <div class="carousel" id="gallery">
                <p>Slide 1 of 3: the summer tournament.</p>
            </div>
            <button type="button">Previous photo</button>
            <button type="button">Next photo</button>
        </section>

        <!-- manual/re-authenticating, manual/no-timing, manual/help: a sign-in form -->
        <form action="/login" method="post">
            <h2>Sign in</h2>
            <p><label for="user">Member number</label> <input id="user" name="user" type="text" autocomplete="username"></p>
            <p><label for="pass">Password</label> <input id="pass" name="pass" type="password" autocomplete="current-password"></p>
            <p><button type="submit">Sign in</button></p>
        </form>

        <!-- manual/interruptions: a live region announcing updates -->
        <div role="status" aria-live="polite" id="news">Next event: Saturday.</div>
    </main>
    <footer><p>Example Club footer</p></footer>
    <script>
        // manual/motion-actuation: shake to refresh the photos
        window.addEventListener('devicemotion', function (event) {
            if (event.acceleration && event.acceleration.x > 20) { location.reload(); }
        });
    </script>
</body>
</html>

This page is generated from the rule catalogue and the rule contracts; see therule overview for how the outcome classes are derived.