Touch Events (swipe) using Stimulus
This article was originally published on Rails Designer The time you build and design web-apps for the desktop, without touch events, has been long gone. Users expect features to work on their touch devices (phones, tablets) just as well. In this article I want to explore two features where touch events can be used: (image) carousels; tinder-like, left- and right card swipes. Something like this (view the gif in all its glory on the original article): (don't hate for disliking the first cat!) Because there is a lot of overlap with these two features I am also going to explore inheritance, meaning one Stimulus controller inherits functionality from another class (just like Ruby's UsersController < ApplicationController). As most of the time with such features, let's start with the HTML as it helps to guide what functionality is needed (this HTML is using Tailwind CSS, but that is optional): Previous Next Easy enough, right? The HTML is already telling pretty much how the carousel controller will look like: import { Controller } from "@hotwired/stimulus" export default class extends Controller { static targets = ["container", "slide"] static values = { index: { type: Number, default: 0 } } next() { this.indexValue = (this.indexValue + 1) % this.totalSlides } previous() { this.indexValue = (this.indexValue - 1 + this.totalSlides) % this.totalSlides } // private indexValueChanged() { const offset = this.indexValue * -100 this.containerTarget.style.transform = `translateX(${offset}%)` } get totalSlides() { return this.slideTargets.length } } The next and previous methods handle circular navigation in the carousel where next increments the indexValue and previous decrements it, both using the modulo operator (%) with the value from totalSlides to wrap around to the beginning/end, so the indexValue always stays within valid bounds (0 to totalSlides - 1). Feel like JavaScript concepts like modulo is still going over your head? Check out JavaScript For Rails Developers.

This article was originally published on Rails Designer
The time you build and design web-apps for the desktop, without touch events, has been long gone. Users expect features to work on their touch devices (phones, tablets) just as well.
In this article I want to explore two features where touch events can be used:
- (image) carousels;
- tinder-like, left- and right card swipes.
Something like this (view the gif in all its glory on the original article):
(don't hate for disliking the first cat!)
Because there is a lot of overlap with these two features I am also going to explore inheritance, meaning one Stimulus controller inherits functionality from another class (just like Ruby's UsersController < ApplicationController
).
As most of the time with such features, let's start with the HTML as it helps to guide what functionality is needed (this HTML is using Tailwind CSS, but that is optional):
data-controller="carousel" data-carousel-index-value="0" class="relative w-full max-w-lg mx-auto">
class="overflow-hidden">
data-carousel-target="container" class="flex transition-transform duration-300">
- data-carousel-target="slide" class="w-full shrink-0">
src="https://unsplash.com/photos/NRQV-hBF10M/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzQyNzc0MDI4fA&force=true&w=640" alt="body of water surrounded by trees" class="object-cover w-full h-64">
- data-carousel-target="slide" class="w-full shrink-0">
src="https://unsplash.com/photos/1Z2niiBPg5A/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzQyNzg4MDM2fA&force=true&w=640" alt="foggy mountain summit" class="object-cover w-full h-64">
- data-carousel-target="slide" class="w-full shrink-0">
src="https://unsplash.com/photos/78A265wPiO4/download?ixid=M3wxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNzQyNzg1NzQyfA&force=true&w=640" alt="landscape photography of mountain hit by sun rays" class="object-cover w-full h-64">
Easy enough, right? The HTML is already telling pretty much how the carousel
controller will look like:
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["container", "slide"]
static values = {
index: { type: Number, default: 0 }
}
next() {
this.indexValue = (this.indexValue + 1) % this.totalSlides
}
previous() {
this.indexValue = (this.indexValue - 1 + this.totalSlides) % this.totalSlides
}
// private
indexValueChanged() {
const offset = this.indexValue * -100
this.containerTarget.style.transform = `translateX(${offset}%)`
}
get totalSlides() {
return this.slideTargets.length
}
}
The next
and previous
methods handle circular navigation in the carousel where next
increments the indexValue
and previous
decrements it, both using the modulo operator (%) with the value from totalSlides
to wrap around to the beginning/end, so the indexValue
always stays within valid bounds (0 to totalSlides - 1).
Feel like JavaScript concepts like modulo is still going over your head? Check out JavaScript For Rails Developers.