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

Fix Modal focus jumping from child to itself #2443

Merged
merged 7 commits into from
Feb 20, 2025
Merged

Conversation

r100-stack
Copy link
Member

@r100-stack r100-stack commented Feb 19, 2025

Changes

A user reported that since 3.17.0, when typing in a controlled input inside a Modal, the focus jumps from the input to the role="dialog" whenever a character is typed. On investigating it seems to be a regression in 3.17.0 because of #2391.

The issue was that onEnter was being called each time the ref function was being called. Thus, onEnter was calling .focus() on the dialog multiple times.

Looks like the ref function was being called multiple times because of the <FocusTrap>. Since focus trap is enabled by default in Modal but not in Dialog, this issue was there in the Modal but not in the Dialog.

The exact issue is the cloneElementWithRef part:

{cloneElementWithRef(children, () => ({ ref: childRef }))}

Memoizing children too didn't work. So I removed the cloning by adding the ref to the first focus trap div and then accessing the children element with firstFocusTrapRef.current?.nextElementSibling. (4dde95f).

Testing

Confimed in a playground similar to the user's to confirm that the focus jump does not happen in Dialog and Modal.

Code
import * as React from 'react';
import {
  Button,
  Dialog,
  InputGroup,
  LabeledInput,
  Modal,
  ModalButtonBar,
  ModalContent,
} from '@itwin/itwinui-react';

export default function App() {
  const [isModalOpen, setIsModalOpen] = React.useState(false);
  const [isDialogOpen, setIsDialogOpen] = React.useState(false);
  const [value, setValue] = React.useState('');

  return (
    <>
      <Button styleType='high-visibility' onClick={() => setIsModalOpen(true)}>
        Open Modal
      </Button>
      <Button styleType='high-visibility' onClick={() => setIsDialogOpen(true)}>
        Open Dialog
      </Button>

      <Modal
        isOpen={isModalOpen}
        title={'Modal title'}
        onClose={() => setIsModalOpen(false)}
        closeOnEsc
        closeOnExternalClick
      >
        <ModalContent>
          <InputGroup>
            <LabeledInput
              label='Input label'
              value={value}
              onChange={(event) => setValue(event.target.value)}
            />
          </InputGroup>
        </ModalContent>
        <ModalButtonBar>
          <Button styleType='high-visibility'>Create</Button>
          <Button>Cancel</Button>
        </ModalButtonBar>
      </Modal>

      <Dialog
        isOpen={isDialogOpen}
        onClose={() => setIsDialogOpen(false)}
        closeOnEsc
        isDismissible
      >
        <Dialog.Main>
          <Dialog.TitleBar titleText='Best dialog ever' />
          <Dialog.Content>
            <InputGroup>
              <LabeledInput
                label='Input label'
                value={value}
                onChange={(event) => setValue(event.target.value)}
              />
            </InputGroup>
          </Dialog.Content>
          <Dialog.ButtonBar>
            <Button styleType='high-visibility'>Primary</Button>
            <Button>Secondary</Button>
          </Dialog.ButtonBar>
        </Dialog.Main>
      </Dialog>
    </>
  );
}

Also added small e2e tests for Modal and Dialog to confirm this.

Docs

Added a changeset.

After PR TODOs

  • Investigate if cloneElementWithRef causes re-renders and any problems associated with it (#2443 (comment))

@r100-stack r100-stack self-assigned this Feb 19, 2025
@r100-stack r100-stack changed the title Fix Modal/Dialog focus jumping from child to dialog Fix Modal focus jumping from child to dialog Feb 19, 2025
@r100-stack r100-stack marked this pull request as ready for review February 19, 2025 22:25
@r100-stack r100-stack requested a review from a team as a code owner February 19, 2025 22:25
@r100-stack r100-stack requested review from mayank99 and smmr-dn and removed request for a team February 19, 2025 22:25
@r100-stack r100-stack changed the title Fix Modal focus jumping from child to dialog Fix Modal focus jumping from child to itself Feb 19, 2025
@r100-stack r100-stack removed the request for review from smmr-dn February 19, 2025 22:25
@mayank99 mayank99 linked an issue Feb 20, 2025 that may be closed by this pull request
1 task
@r100-stack r100-stack merged commit 7f6d607 into main Feb 20, 2025
17 of 18 checks passed
@r100-stack r100-stack deleted the r/modal-focus-bug-fix branch February 20, 2025 18:33
@imodeljs-admin imodeljs-admin mentioned this pull request Feb 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Text input in a modal dialog loses focus
2 participants