embla-carousel: Create an option to block excessive scrolling

Hi @davidjerleke!

Embla currently has ways to remove the leading and trailing blanks from the Slider (containsScroll: true), but still allow for excessive scrolling. It would be interesting to add an option to block this scroll and stop it when it reaches the end or beginning of the Slider. I would like to know what you think of this idea

Below is the example of the “excessive scroll” I am referring to

Captura de Tela (21)

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 34 (16 by maintainers)

Most upvoted comments

@alexeymolchan, @EarthlingDavey, @ameytessact, @sudorock does this work for v8?

TypeScript

emblaApi.on('scroll', (emblaApi) => {
  const {
    limit,
    target,
    location,
    offsetLocation,
    scrollTo,
    translate,
    scrollBody
  } = emblaApi.internalEngine()

  let edge: number | null = null

  if (limit.reachedMax(location.get())) edge = limit.max
  if (limit.reachedMin(location.get())) edge = limit.min

  if (edge !== null) {
    offsetLocation.set(edge)
    location.set(edge)
    target.set(edge)
    translate.to(edge)
    translate.toggleActive(false)
    scrollBody.useDuration(0).useFriction(0)
    scrollTo.distance(0, false)
  } else {
    translate.toggleActive(true)
  }
})

VanillaJs

emblaApi.on('scroll', (emblaApi) => {
  const {
    limit,
    target,
    location,
    offsetLocation,
    scrollTo,
    translate,
    scrollBody
  } = emblaApi.internalEngine()

  let edge

  if (limit.reachedMax(location.get())) edge = limit.max
  if (limit.reachedMin(location.get())) edge = limit.min

  if (edge !== null) {
    offsetLocation.set(edge)
    location.set(edge)
    target.set(edge)
    translate.to(edge)
    translate.toggleActive(false)
    scrollBody.useDuration(0).useFriction(0)
    scrollTo.distance(0, false)
  } else {
    translate.toggleActive(true)
  }
})

Hi @joeyvanlierop, @jeiea,

To anyone wanting to block excessive scrolling: You can use the following code snippet:

const embla = EmblaCarousel(emblaNode, { skipSnaps: false });

const preventEdgeScrolling = (embla) => {
  const { limit, target, location, scrollTo } = embla.internalEngine();

  return () => {
    if (limit.reachedMax(target.get())) {
      if (limit.reachedMax(location.get())) location.set(limit.max);
      target.set(limit.max);
      scrollTo.distance(0, false);
    }
    if (limit.reachedMin(target.get())) {
      if (limit.reachedMin(location.get())) location.set(limit.min);
      target.set(limit.min);
      scrollTo.distance(0, false);
    }
  };
};

embla.on("scroll", preventEdgeScrolling(embla));

Cheers, David

Hello Laks (@LaksCastro) and Joey (@joeyvanlierop)!

Thank you for your question Joey. The answer to your question is no, not yet. But I’ve quite recently added this to my list of things to investigate, together with issue #38, because it seems like these issues are getting a bit of traction. Please note that I can’t promise any outcome but I will at least look into it further.

I can’t give an ETA for this though. Public feature requests are progressing quite slow right now due to lack of time.

I hope you understand.

Best, David

Hi @yunyu,

Thanks for your question. You can use the following code snippet. Please note that dangerouslyGetEngine in that snippet has been renamed to internalEngine from v6 and up.

Best, David

Thank you for the GIF @jeiea. It makes much more sense what you mean now.

So I’m curious why you prefer one over the other. I read above comments again and got the keyword stiff feeling. Of course if user’s drag is ignored completely at the scroll end it can give stiff feeling. But I don’t think it is a problem and maybe android users familiar to that.

One of the main reasons for building this library is because I wasn’t satisfied with how other libraries handle drag events. They’re in my opinion very stiff and only measure drag direction, and not force. It almost feels like you’re trying to move a refrigerator when dragging them. This is in my opinion bad UX and that’s why I prefer a fluid carousel. The speed and duration of the scrolling should be proportional to how vigorous the drag gesture is.

I haven’t considered the overscroll indicator up until now and I’m willing to try it out. Can’t promise anything and give an ETA though. But I will spend some time to see what I can come up with and if it fits the Embla vision.

Best, David

Hey @davidjerleke. I am running into the same jitter issue using the code you provided, it appears to be reproducible in Chrome, FF and Safari. If you have a moment to take a look I’d really appreciate any help.

https://codepen.io/ryanpilbeam/pen/XWOGwMj

Thanks!

@EarthlingDavey that’s weird 🙂. Glad to hear that it works now. Let me know if you run in to trouble on any device or similar and I’ll have another look and think of something.

Best, David

@EarthlingDavey thanks for testing. I’ll have a look at it again when possible.

@ameytessact I’m sorry, I deleted it because it never really worked.

In essence it was an on scroll listener that added a class to the embla component if the limit had been hit. It had a setTimeout to remove the class after 100ms. The css for class was something like transition: transform 50ms.

@davidjerleke Thank you! On MacOS it looks good in chrome, but it stutters when the limits are hit in Firefox & Safari.

@davidjerleke great to see the v8 work. I’ve upgraded really easilly. Cool that we don’t need clickAllowed any more 😃

If you have time, could I have some pointers on how I can improve the above script for v8?

I’d be up for a hard limit or tightening the elasticity.

I’ve naively added a class for css slow transforms when the limit is hit in an attempt to debounce the jitter effect.

But, I’d like to do something a bit better, any suggestion would be welcomed.

Cheers

Hello @LaksCastro!

I hope you’re all well 👍🏻. Sorry for the slow response here. So an update on this issue:

I’ve tested to achieve what you want locally but it kind of goes against Embla’s vision because Embla measures how rigorously a user drags the carousel in contrast to most other carousel libs. Most other libs only measure the drag direction and just assume the carousel should scroll one slide forward/backward. This is why they feel unnatural and very stiff. Overriding the drag force and blocking leading and trailing excessive scrolling would make the carousel feel unnatural.

However, Embla version 3 will soon be released where you can access the actual engine through the API. This will enable you to achieve what you want. As soon as I’ve released version 3 I will put together a CodeSandbox for you in order to demonstrate how to achieve what you want with just a few lines of code.

I hope this makes sense.

Best, David

Exactly, totally block, as shown in this short video I recorded from a Slider mobile

Thank you, @davidcetinkaya