skip to Main Content

I am trying to focus Parent input box after a Dialog box is popped up. I tried passing Parent’s ref to child and focus from child but hard time making it to work.

I’d appreciate your help.

Code sandbox: https://codesandbox.io/s/modal-components-react-custom-hooks-forked-iyumhx?file=/src/Modal.js

Code:

const App = () => {
  const { isShowing, toggle, setIsShowing } = useModal();
  const [input, setInput] = useState("");
  const ref = useRef();

  useEffect(() => {
    if (input != "") setIsShowing(true);
  }, [input]);

  return (
    <div className="App">
      <input type="text" ref={ref} onChange={(e) => setInput(e.target.value)} />
      <Modal
        isShowing={isShowing}
        hide={toggle}
        forwardRef={ref}
        input={input}
      />
    </div>
  );
};

here on Console.log ref, I can see the Ref is defined but the focus function does not work.

const Modal = ({ isShowing, hide, forwardRef, input }) => {
  useEffect(() => {
    console.log(forwardRef);
    forwardRef.current.focus();
  }, []);

  return (
    <>
      <M
        isOpen={isShowing}
        role="dialog"
        autoFocus={true}
        centered={true}
        size="lg"
        // query={query}
        scrollable={false}
      >
        From Parent {input}
      </M>
    </>
  );
};

3

Answers


  1. Change your modal useEffect to

    useEffect(() => {
      if (forwardRef.current) {
        forwardRef.current.focus();
      }
    }, [forwardRef]);
    
    Login or Signup to reply.
  2. Put autofocus false on the modal. This will prevent the modal from stealing focus from the input.

    Login or Signup to reply.
  3. The issue is that the modal from reactstrap library has autoFocus={true} by default, you have to set it to false, you also don’t need help from useRef. here is working code:

    App.jsx

    import React, { useState } from "react";
    import ReactDOM from "react-dom";
    import Modal from "./Modal";
    import "./styles.css";
    import { useBoolean } from "./useBoolean";
    
    const App = () => {
      const [isModalOpen, openModal, closeModal] = useBoolean();
      const [inputValue, setInputValue] = useState("");
    
      return (
        <div className="App">
          <input
            type="text"
            value={inputValue}
            onChange={(e) => {
              if (e.target.value !== "") openModal();
              else closeModal();
    
              setInputValue(e.target.value);
            }}
          />
          <Modal isOpen={isModalOpen} inputValue={inputValue} />
        </div>
      );
    };
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<App />, rootElement);
    

    Modal.jsx

    import React from "react";
    import { Modal as M } from "reactstrap";
    
    const Modal = ({ isOpen, inputValue }) => {
      return (
        <M
          isOpen={isOpen}
          autoFocus={false} // THIS PART WAS THE ISSUE, THIS SHOULD BE FALSE!
          centered={true}
          size="lg"
          scrollable={false}
        >
          Input: {inputValue}
        </M>
      );
    };
    
    export default Modal;
    

    useBoolean.js

    import { useCallback, useState } from "react";
    
    export const useBoolean = () => {
      const [value, setValue] = useState(false);
      const onToggleOn = useCallback(() => setValue(true), []);
      const onToggleOff = useCallback(() => setValue(false), []);
    
      return [value, onToggleOn, onToggleOff];
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search