---
title: v-touch-swipe directive
related:
  - title: v-touch-repeat directive
    path: touch-repeat.md
  - title: v-touch-pan directive
    path: touch-pan.md
  - title: v-touch-hold directive
    path: touch-hold.md
---
Quasar offers full-featured Vue directives that can totally replace libraries like Hammerjs: `v-touch-pan`, `v-touch-swipe`, `v-touch-hold` and even `v-touch-repeat`.

> **These directives also work with mouse events, not only touch events**, so you are able to build cool functionality for your App on desktops too.

We will be describing `v-touch-swipe` on the lines below.

## TouchSwipe API

### Directive Value

- `value` (Function, optional)
  Handler for swipe (use undefined to disable)
  Function signature: `(details?: object) => void`
  Examples:
    - `({ evt, touch, mouse, direction, duration, distance }) => { /* ... */ }`
  Params:
    - `details` (object, optional)
      Event details
      Object shape:
        - `evt` (Event, optional)
          Original JS event Object
        - `touch` (boolean, optional)
          Triggered by a touch event
        - `mouse` (boolean, optional)
          Triggered by a mouse event
        - `direction` (string, optional)
          Direction of movement
          Accepts: `'up'`, `'right'`, `'down'`, `'left'`
        - `duration` (number, optional)
          How long it took to trigger the event (in milliseconds)
        - `distance` (object, optional)
          Absolute distance (in pixels) since movement started from initial point
          Object shape:
            - `x` (number, optional)
              Absolute distance horizontally
            - `y` (number, optional)
              Absolute distance vertically

### Directive Argument

- `arg` (string, optional), default `'6e-2:6:50'`
  x:y:z, where x is minimum velocity (dist/time; please use float without a dot, example: 6e-2 which is equivalent to 6 * 10^-2 = 0.06), y is minimum distance on first move on mobile, z is minimum distance on desktop until deciding if it's a swipe indeed
  Examples: `v-touch-swipe:7e-2:10:100="fnToCall"`

### Directive Modifiers

- `capture` (boolean, optional)
  Use capture for touchstart event
- `mouse` (boolean, optional)
  Listen for mouse events too
- `mouseCapture` (boolean, optional)
  Use capture for mousedown event
- `horizontal` (boolean, optional)
  Catch horizontal (left/right) movement
- `vertical` (boolean, optional)
  Catch vertical (up/down) movement
- `up` (boolean, optional)
  Catch swipe to up
- `right` (boolean, optional)
  Catch swipe to right
- `down` (boolean, optional)
  Catch swipe to down
- `left` (boolean, optional)
  Catch swipe to left

## Usage

Swipe with your mouse on the area below to see it in action. If using a mouse, you need to do it quick.

> [!TIP]
> A swipe that starts on a draggable element is ignored, so the native drag does not fight the gesture. Images and links are draggable by default: if your content contains an `<img>`, a `<router-link>` or an `<a>`, add `draggable="false"` to them.

Example "All directions":

```vue
<template>
  <div class="row justify-center">
    <q-card
      v-touch-swipe.mouse="handleSwipe"
      class="custom-area cursor-pointer bg-primary text-white shadow-2 relative-position row flex-center"
    >
      <div v-if="info" class="custom-info">
        <pre>{{ info }}</pre>
      </div>
      <div v-else class="text-center">
        <q-icon name="arrow_upward" />
        <div class="row items-center">
          <q-icon name="arrow_back" />
          <div>Swipe in any direction</div>
          <q-icon name="arrow_forward" />
        </div>
        <q-icon name="arrow_downward" />
      </div>
    </q-card>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const info = ref(null)

function handleSwipe({ evt, ...newInfo }) {
  info.value = newInfo

  // native Javascript event
  console.log(evt)
}
</script>

<style lang="sass" scoped>
.custom-area
  width: 90%
  height: 180px
  border-radius: 3px
  padding: 8px

.custom-info pre
  width: 180px
  font-size: 12px
  line-height: 1.2
</style>
```

Example "One direction only":

```vue
<template>
  <div class="row justify-center">
    <q-card
      v-touch-swipe.mouse.right="handleSwipe"
      class="custom-area cursor-pointer bg-primary text-white shadow-2 relative-position row flex-center"
    >
      <div v-if="info" class="custom-info">
        <pre>{{ info }}</pre>
      </div>
      <div v-else>
        Swipe to right only
        <q-icon name="arrow_forward" />
      </div>
    </q-card>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const info = ref(null)

function handleSwipe({ evt, ...newInfo }) {
  info.value = newInfo

  // native Javascript event
  console.log(evt)
}
</script>

<style lang="sass" scoped>
.custom-area
  width: 90%
  height: 180px
  border-radius: 3px
  padding: 8px

.custom-info pre
  width: 180px
  font-size: 12px
  line-height: 1.2
</style>
```

Example "Several directions":

```vue
<template>
  <div class="row justify-center">
    <q-card
      v-touch-swipe.mouse.up.left="handleSwipe"
      class="custom-area cursor-pointer bg-primary text-white shadow-2 relative-position row flex-center"
    >
      <div v-if="info" class="custom-info">
        <pre>{{ info }}</pre>
      </div>
      <div v-else class="text-center">
        <q-icon name="arrow_upward" />
        <div class="row items-center">
          <q-icon name="arrow_back" />
          <div>Swipe up or left</div>
        </div>
      </div>
    </q-card>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const info = ref(null)

function handleSwipe({ evt, ...newInfo }) {
  info.value = newInfo

  // native Javascript event
  console.log(evt)
}
</script>

<style lang="sass" scoped>
.custom-area
  width: 90%
  height: 180px
  border-radius: 3px
  padding: 8px

.custom-info pre
  width: 180px
  font-size: 12px
  line-height: 1.2
</style>
```

### Handling Mouse Events

When you want to handle mouse events too, use the `mouse` modifier:

```html
<div v-touch-swipe.mouse="userHasSwiped">...</div>
```

### Inhibiting TouchSwipe

When you want to inhibit TouchSwipe, you can do so by stopping propagation of the `touchstart` / `mousedown` events from the inner content:

```html
<div v-touch-swipe.mouse="userSwiped">
  <!-- ...content -->
  <div @touchstart.stop @mousedown.stop>
    <!--
      TouchSwipe will not apply here because
      we are calling stopPropagation() on touchstart
      and mousedown events
    -->
  </div>
  <!-- ...content -->
</div>
```

However, if you are using `capture` or `mouseCapture` modifiers then events will first reach the TouchHold directive then the inner content, so TouchSwipe will still trigger.

### Events after TouchSwipe triggers

Once a swipe is recognized, the directive consumes the events that follow it, so that a swipe does not also count as a tap or as a click, be it on the element itself or on any of its parents. It stops every subsequent `touchmove` / `mousemove` and then the event that ends the gesture: `touchend` for touch events and `mouseup` for mouse events.

This means that `@touchmove`, `@touchend` and `@mouseup` listeners on the element will not be called after a swipe has been recognized. They are still called when the movement does not qualify as a swipe. Should you need them in both cases, listen for them in the capture phase:

```html
<div v-touch-swipe="userHasSwiped" @touchend.capture="userHasLifted">
  <!-- ...content -->
</div>
```
