Skip to content

Interactive elements beneath overlay are not "blocked" in iOS #180

@matt-joecoffee

Description

@matt-joecoffee

Hi,

Great little library. I really love the bottom sheet. However, I'm seeing an issue in Safari on iOS, where clicking the overlay to close the bottom sheet is not being stopPropagated. Any interactive element under the overlay is triggered instead.

In your Basic example, you can see this by tapping the overlay atop the Open button to close the bottom sheet. It closes and immediately reopens the sheet, because the Open button is also being tapped. So, really easy to observe the issue. Hopefully also easy to fix.

Activity

changed the title [-]Interactive elements beneath overlay are not "blocked"[/-] [+]Interactive elements beneath overlay are not "blocked" in iOS[/+] on Oct 28, 2021
matt-joecoffee

matt-joecoffee commented on Nov 16, 2021

@matt-joecoffee
Author

Sadly, this issue renders this package completely unusable for us. Is this still being maintained?

anirudh-wal

anirudh-wal commented on Nov 25, 2021

@anirudh-wal

Facing the same issue. This is such a great library, but this issue is something that needs to be addressed for our implementation. I am hopeful that this will get resolved soon.

anirudh-wal

anirudh-wal commented on Nov 25, 2021

@anirudh-wal

@stipsan Please see if this can be addressed. Or if we need to handle onDismiss in a different way.

anirudh-wal

anirudh-wal commented on Nov 26, 2021

@anirudh-wal

@matt-joecoffee
I did a workaround for now and it seems to be working fine. I added a div to the sibling prop and made that as an overlay and disabled the blocking prop.

sibling={
    <div
      className="custom-backdrop"
      onClick={e => {
        e.preventDefault();
        e.stopPropagation();
        if (toggle) {
          toggle();
          sheetRef.current.snapTo(0);
        }
      }}
    />
}

For the overlay to look and work as the library, I just copied the overlay CSS from the library and updated a few styles. Specifically the opacity prop. I added transition and it looks and works almost similar. Added that CSS here for reference.

[data-rsbs-root] {
  .custom-backdrop {
    z-index: 999999;
    overscroll-behavior: none;
    touch-action: none;
    position: fixed;
    right: 0;
    bottom: 0;
    left: 0;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    top: -60px;
    bottom: -60px;
    background: none;
    background-color: rgba(0, 0, 0, 0.6);
    will-change: opacity;
    cursor: pointer;
    opacity: 1;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    transition: opacity 0.5s ease-in-out;
  }

  &[data-rsbs-is-dismissable="false"] .custom-backdrop {
    cursor: ns-resize;
  }

  &[data-rsbs-state="closing"] .custom-backdrop {
    opacity: 0;
  }
}
denizmersinlioglu

denizmersinlioglu commented on Mar 14, 2022

@denizmersinlioglu

Hi, here is our workaround to the issue.
TLDR: Use a background wrapper to stop click event propagation.

const Modal: React.FC<{visible: boolean}> = ({ visible }) => {
  const [showBackground, setShowBackground] = useState(false);
  
  // 100 ms delay to remove background
  useEffect(() =>  setTimeout(() => setShowBackground(visible), 100)}, [visible]);
  
  return (
    <Background
          onClick={(event) => event.stopPropagation()}
          visible={showBackground}
        >
       <BottomSheet .... />
    </Background>
}
  
const Background = styled.div<{ visible: boolean }>`
    background-color: red; // You can keep it red if you like it
    bottom: 0px;
    display: ${({ visible }) => (visible ? "block" : "none")};
    left: 0px;
    position: absolute;
    right: 0px;
    top: 0px;
`;
signorbusi

signorbusi commented on Jun 1, 2022

@signorbusi

Does anyone understand why this is happening? I don't understand why the tap is going through the backdrop... And mobile Safari seems to be the only browser behaving like this. Safari desktop works fine.

signorbusi

signorbusi commented on Jun 2, 2022

@signorbusi

After some investigation I found the root of the problem: The Reach UI portal that contains the bottom sheet needs to have the full height. So by adding this CSS globally the problem is fixed:

reach-portal {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
  }

I can't guarantee that this will not break other things though, but so far everything looks good.

aeharding

aeharding commented on Aug 8, 2022

@aeharding

@signorbusi thanks, that worked great for me! I just had to update it to have a z-index higher than my header (that was being clicked through to).

For me-

  // Hack for https://github.com/stipsan/react-spring-bottom-sheet/issues/180#issuecomment-1144537142
  reach-portal {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 100;
  }

Nasty iOS Safari bug :/

added a commit that references this issue on Aug 8, 2022
aeharding

aeharding commented on Aug 8, 2022

@aeharding

Just an update. one of the drawbacks of this method is the page will not be interactable for clicking for about a second after closed. Kinda annoying :/ Looking for a better solution.

mahmutfurkankara

mahmutfurkankara commented on Nov 9, 2022

@mahmutfurkankara

I have faced with same issue. When I click on the backdrop div it propagates the event and causes unintended click on other components. I mix the solutions above and put some logic into it. Here is my way:

  • Create a sibling
  • Give data-rsbs-backdrop="true" to sibling, (we are trying to replace the original backdrop)
  • The original backdrop and overlay has z-index 3 (same for both), change sibling's z-index to 4 (or other number greater than 3), change overlay's z-index to 5 (or other number greater than 4)
  • By doing the stuff above, we put another layer between original backdrop and overlay , so we have the control right now.
  • Do whatever you want in sibling div

(Pay attention to css by the way, especially sibling's css)

I don't know if it breaks something, if it is then forgive me :D

Here is my react component

        <BottomSheet
          open={open}
          className={some-buttomsheet-class}
          sibling={
            <div
              data-rsbs-backdrop="true"
              className={styles.bottomSheetSibling}
              onClick={e => {
                e.preventDefault();
                e.stopPropagation();
                onCancel()
              }}
            />
          }
          scrollLocking
          onDismiss={onCancel}
        >
          {some content}
        </BottomSheet>

Here is my css

.bottomSheetSibling {
  &[data-rsbs-backdrop] {
    z-index: 4;
  }
}
.bottomSheet {

  [data-rsbs-overlay] {
    z-index: 5;
  }
}
erhnml

erhnml commented on Jan 6, 2023

@erhnml

I have faced with same issue. When I click on the backdrop div it propagates the event and causes unintended click on other components. I mix the solutions above and put some logic into it. Here is my way:

  • Create a sibling
  • Give data-rsbs-backdrop="true" to sibling, (we are trying to replace the original backdrop)
  • The original backdrop and overlay has z-index 3 (same for both), change sibling's z-index to 4 (or other number greater than 3), change overlay's z-index to 5 (or other number greater than 4)
  • By doing the stuff above, we put another layer between original backdrop and overlay , so we have the control right now.
  • Do whatever you want in sibling div

(Pay attention to css by the way, especially sibling's css)

I don't know if it breaks something, if it is then forgive me :D

Here is my react component

        <BottomSheet
          open={open}
          className={some-buttomsheet-class}
          sibling={
            <div
              data-rsbs-backdrop="true"
              className={styles.bottomSheetSibling}
              onClick={e => {
                e.preventDefault();
                e.stopPropagation();
                onCancel()
              }}
            />
          }
          scrollLocking
          onDismiss={onCancel}
        >
          {some content}
        </BottomSheet>

Here is my css

.bottomSheetSibling {
  &[data-rsbs-backdrop] {
    z-index: 4;
  }
}
.bottomSheet {

  [data-rsbs-overlay] {
    z-index: 5;
  }
}
.bottomSheet {
 [data-rsbs-backdrop]:not(:first-child) {
   display:none;
 }
}

thank you, I just fixed it by hiding the orjinal backdrop.

ali-h-s21

ali-h-s21 commented on Jan 21, 2023

@ali-h-s21

Here is my simple solution that worked with me just fine. I just added a sibling, and set the 'blocking' to be false.

function MyBottomSheetModal(props: BottomSheetProps) {
  return (
    <BottomSheet
      sibling={
        <div
          data-rsbs-backdrop="true"
          onClick={(e) => {
            e.stopPropagation();
            e.preventDefault();
            props.onDismiss?.();
          }}
        />
      }
      blocking={false}
      {...props}
    />
  );
}
romshiri

romshiri commented on Apr 5, 2025

@romshiri

2025 is here. Is there any proper solution for this? Anyone?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      Participants

      @romshiri@aeharding@denizmersinlioglu@anirudh-wal@erhnml

      Issue actions

        Interactive elements beneath overlay are not "blocked" in iOS · Issue #180 · stipsan/react-spring-bottom-sheet