75

DEMO JSSFIDDLE

  <div class="col-md-4">
          <!--Carousel-->
          <div id="sidebar-carousel-1" class="carousel slide" data-ride="carousel">
            <ol class="carousel-indicators grey">
              <li data-target="#sidebar-carousel-1" data-slide-to="0" class="active"></li>
              <li data-target="#sidebar-carousel-1" data-slide-to="1"></li>
              <li data-target="#sidebar-carousel-1" data-slide-to="2"></li>
            </ol>
            <div class="carousel-inner">
              <div class="item active">
                <a href="" data-lightbox="image-1" title="">
                <img src="http://shrani.si/f/3D/13b/1rt3lPab/2/img1.jpg" alt="...">
                </a>
              </div>
              <div class="item">
                <a href="" data-lightbox="image-1" title="">
                <img src="http://shrani.si/f/S/jE/UcTuhZ6/1/img2.jpg" alt="...">
                </a>                  </div>
              <div class="item">
                <a href="" data-lightbox="image-1" title="">
                <img src="http://shrani.si/f/h/To/1yjUEZbP/img3.jpg" alt="...">
                </a>                  </div>
            </div>
             <!-- Controls -->
        <a class="left carousel-control" href="#sidebar-carousel-1" data-slide="prev">
          <span class="glyphicon glyphicon-chevron-left"></span>
        </a>
        <a class="right carousel-control" href="#sidebar-carousel-1" data-slide="next">
          <span class="glyphicon glyphicon-chevron-right"></span>
        </a>
                  </div><!--/Carousel--></div>

What I want to do is to add left/right touch swipe functionality for mobile devices only. How can I do that?

Also, how do I make prev/next buttons, that appear on hover, smaller for mobile/ipad versions?

Thanks

Mike Causer
  • 8,196
  • 2
  • 43
  • 63
user3187469
  • 1,461
  • 7
  • 23
  • 31

10 Answers10

151

I'm a bit late to the party, but here's a bit of jQuery I've been using:

$('.carousel').on('touchstart', function(event){
    const xClick = event.originalEvent.touches[0].pageX;
    $(this).one('touchmove', function(event){
        const xMove = event.originalEvent.touches[0].pageX;
        const sensitivityInPx = 5;

        if( Math.floor(xClick - xMove) > sensitivityInPx ){
            $(this).carousel('next');
        }
        else if( Math.floor(xClick - xMove) < -sensitivityInPx ){
            $(this).carousel('prev');
        }
    });
    $(this).on('touchend', function(){
        $(this).off('touchmove');
    });
});

No need for jQuery mobile or any other plugins. If you need to adjust the sensitivity of the swipe adjust the 5 and -5.

starball
  • 20,030
  • 7
  • 43
  • 238
Liam
  • 1,860
  • 1
  • 11
  • 18
  • 9
    Great solution, although you have the 'prev' and 'next' inverted. Much lighter-weight than adding a full mobile jQuery solution. Thanks. – Scott 'scm6079' Nov 11 '16 at 03:14
  • 7
    Wow, cool solution! But I have several carousels on a page. So I prefer to use `$(this)` instead of `$(".carousel')` inside the function. And I also have swapped `prev` and `next` :) – Gleb Kemarsky Jan 13 '17 at 10:56
  • 7
    I amended the answer – Liam Feb 02 '17 at 09:39
  • Do we need to make any change to this to use it with bootstrap 4 carousel ? – Fahad Ur Rehman Jan 26 '19 at 16:16
  • @Fahad Yes, this should work for Bootstrap 4. The methods are the same. – Liam Feb 07 '19 at 10:32
  • 1
    Finally! I've tried using the various other methods to make swipe work in Demandware. Their new version, SFRA, has bootstrap-inspired roots, but the other fixes that are supposed to work for bootstrap don't work in Demandware. This was the answer! Thanks! – Leann Jul 30 '19 at 08:22
  • 1
    bless you and jquery. this worked first time with no extra cdn's etc . – Glen Apr 30 '20 at 21:49
  • it only works for Chrome to me, trying in Android Webview and Firefox and it does not work – Miguel Dec 23 '20 at 22:33
  • @Miguel - the answer was recently edited, try my answer before it was edited – Liam Jan 07 '21 at 14:18
  • A million thanks for this! I needed swipe in the 11th-1/2 hour of project delivery. This solution worked perfectly! – kenswdev May 29 '21 at 17:35
  • Just perfect... – Hassan Mehmood Oct 06 '22 at 16:07
111

I needed to add this functionality to a project I was working on recently and adding jQuery Mobile just to solve this problem seemed like overkill, so I came up with a solution and put it on github: bcSwipe (Bootstrap Carousel Swipe).

It's a lightweight jQuery plugin (~600 bytes minified vs jQuery Mobile touch events at 8kb), and it's been tested on Android and iOS.

This is how you use it:

$('.carousel').bcSwipe({ threshold: 50 });
Mark Shiraldi
  • 2,401
  • 3
  • 15
  • 9
  • 1
    OMG!!! THANK YOU!!! YOU SAVED MY LIFE!!! the .carousel approach has issue when sliding but with your code, it works! – Alyssa Reyes Apr 01 '16 at 09:55
  • 3
    @Mark Shiraldi I have tried to use the Bootstrap Carousel Swipe and script and yet it does not work correctly – Roberto Flores Aug 12 '16 at 22:33
  • 2
    Good one Maaark. I just tried this using **Bootstrap v4.0.0-alpha.5 and jQuery 3.1.1**. Swiping is **working fine** on my Android smartphone and rendering automatically on large screens as expected. – Chris O Jan 02 '17 at 05:37
  • Update: I realised this was a mistake in my layout. bcSwipe works great, it's the best solution I've found – Daniel Mar 29 '17 at 18:27
  • @ChrisO so this woeks only with bootstrapv4? – Imnotapotato Jun 29 '17 at 10:52
  • @RickSanchez, Rick according to the github page it is for Bootstrap 3. I have only used it with Boostrap 4. It appears that others have successfully used it on version 3. Ping Mark Shiraldi for more info not found on the github bcSwipe page. Good luck! – Chris O Jun 30 '17 at 15:57
  • Works great for me on Bootstrap 3 as well. Thank you. – iamse7en Sep 22 '17 at 22:25
  • Worked with Bootstrap 4, this must be accepted answer. Thank you! – Arun Basil Lal Jan 13 '18 at 16:34
  • Great, but accidental vertical swipe ruins it. – Alexander Kim Jun 18 '18 at 16:20
  • cant get it to work.. do i just paste the html and script the j.s. at bottom of page? using bs4 – Glen Apr 30 '20 at 21:43
101

UPDATE:

I came up with this solution when I was pretty new to web design. Now that I am older and wiser, the answer Liam gave seems to be a better option. See the next top answer; it is a more productive solution.

I worked on a project recently and this example worked perfectly. I am giving you the link below.

First you have to add jQuery mobile:

http://jquerymobile.com/

This adds the touch functionality, and then you just have to make events such as swipe:

<script>
$(document).ready(function() {
   $("#myCarousel").swiperight(function() {
      $(this).carousel('prev');
    });
   $("#myCarousel").swipeleft(function() {
      $(this).carousel('next');
   });
});
</script>

The link is below, where you can find the tutorial I used:

http://lazcreative.com/blog/how-to/how-to-adding-swipe-support-to-bootstraps-carousel/

Liam
  • 1,860
  • 1
  • 11
  • 18
Abdul Rafay Shaikh
  • 1,358
  • 1
  • 11
  • 23
  • 14
    Definitely follow the advice and build a touch event-only custom jQuery Mobile version at http://jquerymobile.com/download-builder/. Otherwise you will likely break your site if it is not already built for/with jQuery Mobile. – cdonner May 22 '14 at 23:08
  • 17
    I am voting this down due to the heavy-handedness of installing jQuery mobile to solve only one simple issue. For simplicity I suggest the answer by Mark Shiraldi, it is graceful and less code. – nicholas.alipaz Jun 04 '15 at 15:38
  • 1
    @nicholas.alipaz well, it looks like you're right. Installing completly new grid system for such small feature is not a good solution. – David Jul 07 '15 at 07:09
  • 1
    I don't like this solution, because the slide does not "stick" to your finger as you move over it. It's not user friendly. – Wouter Nov 18 '15 at 15:43
5

With bootstrap 4.2 its now very easy, you just need to pass the touch option in the carousel div as data-touch="true", as it accepts Boolean value only.

As in your case update bootstrap to 4.2 and paste(Or download source files) the following in exact order :

    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

and then add the touch option in your bootstrap carousel div

    <div id="sidebar-carousel-1" class="carousel slide" data-ride="carousel" data-touch="true">
ADITYA HAZARIKA
  • 300
  • 1
  • 4
  • 13
  • 1
    hello, I'm using bootstrap 4.5.3 and the touch is native. however it does not work until you touch one of the two arrows to move to the next/previous image; then it starts working, does anyone else has the same problem? thank you in advance :) – Camaleo Dec 10 '20 at 17:18
  • @Camaleo same issue with bootstrap 5. If you set data-bs-ride="carousel" then it responds to swipes even before the cycle begins. If you don't want it to cycle you could set data-bs-interval="9000000000" for 100 days between slides. – AmpersatStrudel Sep 04 '22 at 04:04
4

See this solution: Bootstrap TouchCarousel. A drop-in perfection for Twitter Bootstrap's Carousel (v3) to enable gestures on touch devices. http://ixisio.github.io/bootstrap-touch-carousel/

stan1379
  • 41
  • 1
  • 3
    I really like this approach but I don't think the package is ready for a production setting yet. The carousel has some large bugs like links/modals not working after carouslel initialization etc. – am80l Jul 25 '14 at 17:08
3

If you don't want to use jQuery mobile as like me. You can use Hammer.js

It's mostly like jQuery Mobile without unnecessary code.

$(document).ready(function() {
  Hammer(myCarousel).on("swipeleft", function(){
    $(this).carousel('next');
  });
  Hammer(myCarousel).on("swiperight", function(){
    $(this).carousel('prev');
  });
});
Madan Bhandari
  • 2,094
  • 2
  • 26
  • 46
2

Checked solution is not accurate, sometimes mouse-right-click triggers right-swipe. after trying different plugins for swipe i found an almost perfect one.

touchSwipe

i said "almost" because this plugin does not support future elements. so we would have to reinitialize the swipe call when the swipe content is changed by ajax or something. this plugin have lots of options to play with touch events like multi-finger-touch,pinch etc.

http://labs.rampinteractive.co.uk/touchSwipe/demos/index.html

solution 1 :

$("#myCarousel").swipe( {
            swipe:function(event, direction, distance, duration, fingerCount, fingerData) {

                if(direction=='left'){
                    $(this).carousel('next');
                }else if(direction=='right'){
                    $(this).carousel('prev');
                }

            }
        });

solution 2:(for future element case)

function addSwipeTo(selector){
            $(selector).swipe("destroy");
            $(selector).swipe( {
                swipe:function(event, direction, distance, duration, fingerCount, fingerData) {
                    if(direction=='left'){
                        $(this).carousel('next');
                    }else if(direction=='right'){
                        $(this).carousel('prev');
                    }
                }
            });
}
addSwipeTo("#myCarousel");
Rameez Rami
  • 5,322
  • 2
  • 29
  • 36
2

For anyone finding this, swipe on carousel appears to be native as of about 5 days ago (20 Oct 2018) as per
https://github.com/twbs/bootstrap/pull/25776

https://deploy-preview-25776--twbs-bootstrap4.netlify.com/docs/4.1/components/carousel/

geo
  • 99
  • 4
  • Can you provide some information on how to activate it? I am using 4.1.3 and swiping is not working by default – james Oct 25 '18 at 18:19
  • @binnyb It's probably a pretty shady way of doing it, but I just grabbed the .js from that preview page which works with swipe i.e. https://deploy-preview-25776--twbs-bootstrap4.netlify.com/docs/4.1/dist/js/bootstrap.bundle.js So not quite native but must be close. – geo Oct 26 '18 at 00:53
  • Wow, the diff between Production 4.1.3 and your linked version is so different- 462 differences. A little scary when considering using it. – james Oct 26 '18 at 12:50
  • I was trying to find out a way to implement a "Swipe" event for the carousel, but yes, the functionnality is there (native) but only works if you are on a mobile device. https://getbootstrap.com/docs/4.3/components/carousel/#with-controls – Patrice Poliquin Jul 09 '19 at 13:51
1

Same functionality I prefer than using much heavy jQuery mobile is Carousel Swipe. I suggest directly jump in to source code on github, and copy file carousel-swipe.js in to your project directory.

Use swiper events as bellow:

$('#carousel-example-generic').carousel({
      interval: false 
  });
Shweta
  • 1,212
  • 4
  • 20
  • 36
0

If anyone is looking for the angular version of this answer then I would suggest creating a directive would be a great idea.

NOTE: ngx-bootstrap is used.

import { Directive, Host, Self, Optional, Input, Renderer2, OnInit, ElementRef } from '@angular/core';
import { CarouselComponent } from 'ngx-bootstrap/carousel';

@Directive({
  selector: '[appCarouselSwipe]'
})
export class AppCarouselSwipeDirective implements OnInit {
  @Input() swipeThreshold = 50;
  private start: number;
  private stillMoving: boolean;
  private moveListener: Function;

  constructor(
    @Host() @Self() @Optional() private carousel: CarouselComponent,
    private renderer: Renderer2,
    private element: ElementRef
  ) {
  }

  ngOnInit(): void {
    if ('ontouchstart' in document.documentElement) {
      this.renderer.listen(this.element.nativeElement, 'touchstart', this.onTouchStart.bind(this));
      this.renderer.listen(this.element.nativeElement, 'touchend', this.onTouchEnd.bind(this));
    }
  }

  private onTouchStart(e: TouchEvent): void {
    if (e.touches.length === 1) {
      this.start = e.touches[0].pageX;
      this.stillMoving = true;
      this.moveListener = this.renderer.listen(this.element.nativeElement, 'touchmove', this.onTouchMove.bind(this));
    }
  }

  private onTouchMove(e: TouchEvent): void {
    if (this.stillMoving) {
      const x = e.touches[0].pageX;
      const difference = this.start - x;
      if (Math.abs(difference) >= this.swipeThreshold) {
        this.cancelTouch();
        if (difference > 0) {
          if (this.carousel.activeSlide < this.carousel.slides.length - 1) {
            this.carousel.activeSlide = this.carousel.activeSlide + 1;
          }
        } else {
          if (this.carousel.activeSlide > 0) {
            this.carousel.activeSlide = this.carousel.activeSlide - 1;
          }
        }
      }
    }
  }

  private onTouchEnd(e: TouchEvent): void {
    this.cancelTouch();
  }

  private cancelTouch() {
    if (this.moveListener) {
      this.moveListener();
      this.moveListener = undefined;
    }
    this.start = null;
    this.stillMoving = false;
  }
}

in html:

<carousel appCarouselSwipe>

    ...

</carousel>

Reference

deepchudasama
  • 480
  • 7
  • 18