Skip to content
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

[BUG] - Modal does not adjust position when keyboard appears on iOS #2837

Closed
jalvarezz13 opened this issue Apr 22, 2024 · 39 comments · Fixed by #3691
Closed

[BUG] - Modal does not adjust position when keyboard appears on iOS #2837

jalvarezz13 opened this issue Apr 22, 2024 · 39 comments · Fixed by #3691
Assignees
Labels
📦 Scope : Components Related to the components 🐛 Type: Bug Something isn't working

Comments

@jalvarezz13
Copy link

NextUI Version

2.3.5

Describe the bug

After updating from version 2.2.X to 2.3.X, there is an issue observed on iOS devices where the modal dialog does not adjust its position when the keyboard appears on the screen. As a result, the modal remains in its original position, obscuring the view of the input fields and preventing users from seeing what they are typing. This behavior affects the usability of the application, especially in forms and dialogs requiring user input.

Your Example Website or App

No response

Steps to Reproduce the Bug or Issue

  1. Create a webpage that includes a modal dialog.
  2. Within the modal, include a form with several input fields.
  3. Open the webpage on an iOS device using Safari.
  4. Tap on the input field within the modal to bring up the iOS keyboard.

Notice that when the keyboard appears, the modal remains in its fixed position at the bottom of the screen. The keyboard covers the modal, obscuring the input field and preventing the user from seeing what is being typed.

Expected behavior

The modal should adjust its position when the keyboard appears, moving up to ensure that the input field is visible and the user can see what they are typing.

Screenshots or Videos

No response

Operating System Version

iOS 17.4.1

Browser

Safari

Copy link

linear bot commented Apr 22, 2024

@wingkwong
Copy link
Member

wingkwong commented Apr 22, 2024

@jalvarezz13 can you attach a screenshot and some code? Also can you share how it looked in 2.2.x?

@jalvarezz13
Copy link
Author

The code could be this modal https://nextui.org/docs/components/modal#with-form without "top-center" placement.
I attach a simple demo here:

ios.mp4

@vtsybulin
Copy link

vtsybulin commented Apr 26, 2024

Facing the same issue after bumping to 2.3.5. Seems like a regression, everything worked just fine before update.

@daniel-esserweb
Copy link

Im facing the same issue

@mashnoon33
Copy link

Can also reproduce

@vtsybulin
Copy link

Looks like it's somehow related to the internal implementation of the scroll-blocking behavior within Modal shouldBlockScroll. Unfortunately, I'm short on time to dig into it more, what I ended up doing was disabling shouldBlockScroll completely, and relying on custom implementation, using body-scroll-lock, which is fine for my case, since it's already used in the project. Tho I had to rely on useEffect to make it work, which is unfortunate and I had to mimic <ModalBody /> classnames explicitly as I needed to get a scrollable modal content ref.

const ModalTemplate = <ContentWrapperProps extends TContentWrapperProps, ModalFooterProps extends TModalFooterProps>({ title, children, ModalContentWrapper = Fragment, modalContentWrapperProps, ModalFooter, getModalFooterProps, isLoading, ...modalProps }: IModalTemplateProps<ContentWrapperProps, ModalFooterProps>): ReactElement => {
  const scrollableTargetRef = useRef<HTMLDivElement>(null);

  useEffect(
    (): void => {
      if (modalProps.isOpen && scrollableTargetRef.current) {
        disableBodyScroll(scrollableTargetRef.current);

        return;
      }

      clearAllBodyScrollLocks();
    },
    [modalProps.isOpen],
  );

  return (
    <Modal
      size="2xl"
      backdrop="blur"
      scrollBehavior="inside"
      hideCloseButton
      shouldBlockScroll={false}
      classNames={{
        backdrop: 'top-0 left-0',
      }}
      {...modalProps}
    >
      <ModalContent>
        {(close: () => void): ReactElement => (
          <ModalContentWrapper
            {...modalContentWrapperProps as ContentWrapperProps}
            className="[display:contents]"
          >

            <ModalHeader className="flex flex-col gap-1">
              <div className="flex w-full items-center justify-between gap-2">
                {title}

                <Button
                  variant="light"
                  isIconOnly
                  onPress={close}
                >
                  <CloseIcon />
                </Button>
              </div>
            </ModalHeader>

            /** Explicit <ModalBody /> implementation. class names list was taken from nextui.Modal.ModalBody as is **/
            <div
              className="flex flex-1 flex-col gap-3 overflow-y-auto px-6 py-2"
              ref={scrollableTargetRef}
            >
              {children}
            </div>

            {ModalFooter && (
              <ModalFooterBase>
                <ModalFooter
                  {...(typeof getModalFooterProps === 'function' && getModalFooterProps({
                    close,
                    isLoading,
                  })) as ModalFooterProps}
                />
              </ModalFooterBase>
            )}
          </ModalContentWrapper>
        )}
      </ModalContent>
    </Modal>
  );
};

export default ModalTemplate;

@HastaCs
Copy link

HastaCs commented May 6, 2024

same issue with 2.3.6
2.2.10 is working fine

@jalvarezz13
Copy link
Author

Any update? Thanks!

@jalvarezz13
Copy link
Author

In case it helps... I'm temporarily using @nextui-org/modal in version 2.0.29 until this bug is fixed.

@jalvarezz13
Copy link
Author

jalvarezz13 commented Jun 3, 2024

@jrgarciadev The error persists in version 2.4.0

@dharmveer97
Copy link

dharmveer97 commented Jun 12, 2024

same issue is here #3241

#3241 anybody know how to fix this issue?

@0xAskar
Copy link

0xAskar commented Jun 14, 2024

i'm having the same problem, does anyone have an idea on how to fix it?

@theonlyway
Copy link

i'm having the same problem, does anyone have an idea on how to fix it?

Just use the version of the modal from further up where it works. Install just the individual modal package version above and import the modal from that package instead of the central package

@kamami
Copy link

kamami commented Jun 17, 2024

Same issue with version 2.0.36 of modal.

@dharmveer97
Copy link

@kamami If you want to fix this issue, you can install the individual modal box using version 2.0.0. It is a little bit buggy too, but the keyboard issue does not occur in this version. However, in other versions, the keyboard hides the inputs in all versions.

https://www.npmjs.com/package/@nextui-org/modal

@0xAskar
Copy link

0xAskar commented Jun 19, 2024

@theonlyway thanks! I also just kept the latest version and on mobile screens i adjusted the absolute position as others suggested here.

@erodriguezvesti
Copy link

same issue here, installing @nextui-org/modal@2.0.0 works for now

@daveycodez
Copy link

daveycodez commented Jun 22, 2024

Oof. 2.0.0 fixes this, but scrolling is broken even with scrollBehavior outside if the modal is too big... ruh roh.

EDIT: For scrollBehavior: outside to work you also need placement set to top.... hmm

@dharmveer97
Copy link

TEMP SOLUTION

'use client';

import React, { useEffect, useRef } from 'react';
import {
  Button,
  useDisclosure,
  Modal,
  ModalContent,
  ModalBody,
} from '@nextui-org/react';

import CreateLotForm from '../../components/forms/CreateLotForm';

const AddLotModal = () => {
  const { isOpen, onOpen, onOpenChange, onClose } = useDisclosure();
  const modalBodyRef = useRef(null);

  const handleOpen = () => {
    onOpen();
  };

  useEffect(() => {
    if (modalBodyRef.current) {
      const inputs = modalBodyRef.current.querySelectorAll(
        'input, textarea, select',
      );
      inputs.forEach((input) => {
        input.addEventListener('focus', () => {
          setTimeout(() => {
            input.scrollIntoView({ behavior: 'smooth', block: 'center' });
          }, 300);
        });
      });
    }
  }, [isOpen]);

  return (
    <div>
      <div className="flex flex-wrap gap-3">
        <Button
          variant="flat"
          color="warning"
          onClick={handleOpen}
          className="capitalize"
        >
          Add New
        </Button>
      </div>

      <Modal
        isOpen={isOpen}
        onOpenChange={onOpenChange}
        isDismissable={false}
        scrollBehavior="outside"
        size="5xl"
      >
        <ModalContent>
          {() => (
            <>
              {/* empty div for more space or height */}
              <div className="pt-12 block sm:hidden" />
              <ModalBody ref={modalBodyRef}>
                <CreateLotForm
                  enableReinitialize
                  close={onClose}
                  onSubmit={() => {}}
                />
                {/* empty div for more space or height */}
                <div className="pb-44 block sm:hidden" />
              </ModalBody>
            </>
          )}
        </ModalContent>
      </Modal>
    </div>
  );
};

export default AddLotModal;

@HastaCs
Copy link

HastaCs commented Jul 19, 2024

any update? :(

@ArielBenichou
Copy link

+1

@n-lavrenko
Copy link

any fixes, updates?

@jalvarezz13
Copy link
Author

jalvarezz13 commented Aug 5, 2024

It's been almost 4 months since the bug appeared, and no one from the NextUI organization seems to have addressed it in this thread.

For those who cannot do the same, I recommend installing the NextUI modal component in isolation from the rest. Also, remember to install the following dependencies to avoid potential issues:

  • @nextui-org/modal: ^2.0.29
  • @nextui-org/system: ^2.1.0
  • @nextui-org/theme: ^2.0.0

You can install them with:
yarn add @nextui-org/modal@^2.0.29 @nextui-org/system@^2.1.0 @nextui-org/theme@^2.0.0

@cristyz
Copy link

cristyz commented Aug 15, 2024

I found a solution with css, tested it and it seems to work reasonably, hope it helps too.

BaseModal.tsx

import { Modal } from "@nextui-org/modal";

type BaseModalProps = {} & React.ComponentProps<typeof Modal>;
export function BaseModal({ children, backdrop = "opaque", ...props }: BaseModalProps) {
  return (
    <Modal
      backdrop={backdrop}
      classNames={{
        wrapper: "pb-[65%] landscape:pb-[50vh] landscape:xl:pb-0",
      }}
      isDismissable={false}
      placement="top"
      scrollBehavior="outside"
      {...props}
    >
      {children}
    </Modal>
  );
}

tailwind.config.ts
Add to your theme extension

portrait: {
  raw: "(orientation: portrait)",
},
landscape: {
  raw: "(orientation: landscape)",
},

Usage example

<BaseModal isOpen={isOpen} onOpenChange={onOpenChange}>
  <ModalContent>
    {(onClose) => (
      <>
        <ModalHeader className="flex flex-col gap-1">Title</ModalHeader>
        <ModalBody>
          <span>Your modal body</span>
        </ModalBody>
        <ModalFooter>
          <Button color="danger" variant="light" onPress={onClose}>
            Close
          </Button>
          <Button color="primary" type="submit">
            Save
          </Button>
        </ModalFooter>
      </>
    )}
  </ModalContent>
</BaseModal>

@wingkwong wingkwong added 🐛 Type: Bug Something isn't working 📦 Scope : Components Related to the components labels Aug 17, 2024
@wingkwong wingkwong self-assigned this Aug 17, 2024
@ETOPS7
Copy link

ETOPS7 commented Aug 18, 2024

I had to use “top-center” placement as a temporary solution since the modal does not behave consistently on mobile screens. We are really looking forward to fixing this issue.

@jalvarezz13
Copy link
Author

@wingkwong I see you have self-assigned this issue, are you working on a specific branch you can share? Thanks

@jalvarezz13
Copy link
Author

@cristyz Thank you for sharing the temporal solution, it's not working for my specific use case but it's a good solution for other cases :)

@Vorashil
Copy link

Vorashil commented Aug 22, 2024

I have managed to avoid this by using an external library, which is not ideal, but will do for now.

https://www.npmjs.com/package/use-detect-keyboard-open

const isKeyboardOpen = useDetectKeyboardOpen();
const placement = isKeyboardOpen ? "top" : "auto"

return <MyCustomModal  isOpen={isOpen} placement={placement} onClose={onClose}/>

@hoanmq
Copy link

hoanmq commented Aug 28, 2024

Any update or release plz?

@Jackmekiss
Copy link

Any updates?

@wingkwong
Copy link
Member

I've made the PR, which is currently under review.

@jalvarezz13
Copy link
Author

Thank you so much @wingkwong... I can't wait to see it at the release!

@wingkwong
Copy link
Member

For those who need the fix before the next bug fix release (v.2.4.7), you may use the canary version for the time being (i.e. change the version to 0.0.0-canary-20240901014525 and reinstall).

@daniel-esserweb
Copy link

For those who need the fix before the next bug fix release (v.2.4.7), you may use the canary version for the time being (i.e. change the version to 0.0.0-canary-20240901014525 and reinstall).

This version crash the autocomplete. Any spected date to this new full release?

@wingkwong
Copy link
Member

@daniel-esserweb I recently also noticed that. I may rollback autocomplete change first.

@wingkwong
Copy link
Member

@daniel-esserweb just rollbacked the change and released another canary version. The full release should be available in weekend (tentatively).

@HastaCs
Copy link

HastaCs commented Oct 2, 2024

fixed or news?.. :)

@wingkwong
Copy link
Member

@HastaCs already included in the latest version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
📦 Scope : Components Related to the components 🐛 Type: Bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.