Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Focus plugin .noscroll modifier iOS issues #3038

Closed
tomblanchard opened this issue Jul 13, 2022 Discussed in #3037 · 4 comments
Closed

Focus plugin .noscroll modifier iOS issues #3038

tomblanchard opened this issue Jul 13, 2022 Discussed in #3037 · 4 comments

Comments

@tomblanchard
Copy link

Discussed in #3037

Originally posted by tomblanchard July 13, 2022
It seems that the focus plugin .noscroll modifier no longer prevents body scrolling on iOS - I think this is a new bug from one of the recent 15.x iOS updates because it previously worked flawlessly.

Here's a screencast taken from the Alpine docs example on latest iOS version (15.5):

RPReplay_Final1657717448.mov

I've looked into this and it's related to the disableScrolling function, it's strategy to prevent body scrolling is to set html { overflow: hidden; } - this seems to work everywhere except iOS. Perhaps it's necessary to outsource this to a dedicated library such as body-scroll-lock? At a bare minimum, it'd be good to have the ability to set our own disableScrolling function so we have the ability to override the default.

@danddanddand
Copy link
Contributor

I created a MR for this before but the size and maintenance was concern (#2369).

In my project I just use body-scroll-lock but it's looking like a dead project at this point so it's hard to recommend (willmcpo/body-scroll-lock#257).

@tomblanchard
Copy link
Author

tomblanchard commented Jul 13, 2022

@danddanddand Ah I see, I also understand the size and maintenance concerns, along with the fact that body-scroll-lock is no longer maintained.

I do think it'd be beneficial to introduce an optional interface to override the focus .noscroll disableScrolling function for those of us who would like to use the up to date plugin and want the ability to define our own noscroll functionality. I'm just not sure how that would look, maybe a way to pass the function to the plugin initialisation, e.g:

import Alpine from 'alpinejs'
import focus from '@alpinejs/focus'

function disableScrolling() {
  // body-scroll-lock or some custom noscroll functionality
}
 
Alpine.plugin(focus, disableScrolling)

Either that or a global function or something?

@danddanddand
Copy link
Contributor

danddanddand commented Jul 13, 2022

Most menu/modals that need it have an open and close function already to do other stuff, so in my opinion there is very little advantage to having it in Alpine. It's a bit different than focus trapping which is a lot more code. calling body scroll lock is a one liner.

@tomblanchard
Copy link
Author

I ended up opting out of using the Focus .noscroll modifier and creating my own custom, dedicated plugin which uses body-scroll-lock:

./plugins/noscroll.js
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock';

export default function(Alpine) {
  Alpine.directive('noscroll', Alpine.skipDuringClone(
    (el, { expression }, { effect, evaluateLater }) => {
      let evaluator = evaluateLater(expression);

      let oldValue = false;

      let undoDisableScrolling = () => {};

      effect(() => evaluator(value => {
        if (oldValue === value) return;

        // Start noscroll.
        if (value && ! oldValue) {
          setTimeout(() => {
            undoDisableScrolling = disableScrolling(el);
          });
        }

        // Stop noscroll.
        if (! value && oldValue) {
          undoDisableScrolling();
          undoDisableScrolling = () => {};
        }

        oldValue = !! value;
      }));
    }
  ));
};

function disableScrolling(el) {
  disableBodyScroll(el, { reserveScrollBarGap: true });

  return () => {
    enableBodyScroll(el);
  };
};

With this plugin in place, I replace this:

<div
  x-trap.noscroll="isActive"
></div>

With this:

<div
  x-trap="isActive"
  x-noscroll="isActive"
></div>

Not the cleanest solution, but it works and uses a familiar API/pattern.

@alpinejs alpinejs locked and limited conversation to collaborators Nov 24, 2022
@joshhanley joshhanley converted this issue into discussion #3295 Nov 24, 2022

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants