---
title: v-touch-swipe directive
desc: >-
  Vue directive which triggers an event when the user swipes with the finger or
  mouse on a component or element.
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) => unknown`
  Examples:
    - `({ evt, touch, mouse, direction, duration, distance }) => { /* ... */ }`

### 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]
> If your content also has images, you might want to add `draggable="false"` to them, otherwise the native browser behavior might interfere in a negative way.

### All directions

```vue
<template>
  <div class="q-pa-md 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>
```

### One direction only

```vue
<template>
  <div class="q-pa-md 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>
```

### Several directions

```vue
<template>
  <div class="q-pa-md 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>
```
