skip to Main Content

I am trying to achieve the following using React.

  • The moment user will start typing in the input box below, a modal
    will appear and user will continue to type there without clicking on
    the Modal’s input box

  • Once user will click backspace and clear the Modal’s input box, it closes the box and focus goes back to the main input empty box.

Reason on using two Input states: It will look odd to see the parent input box getting updated behind the Dialog Box.

enter image description here

Code : https://codesandbox.io/s/modal-reactstrap-forked-r2sns1?file=/src/modal.tsx:0-1658

Parent Component

 const App = () => {
  const [openDialog, setDialog] = useState({
    isModalOpen: false,
    value: ""
  });

  const toggle = () => {
    setDialog({ isModalOpen: false, value: "" });
  };

  return (
    <div className="App">
      <ModalExample
        openDialog={openDialog.isModalOpen}
        query={openDialog.value}
        toggle={() => toggle()}
      />
      <input
        type="text"
        value={openDialog.value}
        onChange={(e) =>
          setDialog({ isModalOpen: true, value: e.target.value })
        }
      ></input>
    </div>
  );
};

Dialog Component

const Dialog = ({ openDialog, query, toggle }: any) => {
  const ref = useRef<HTMLInputElement | null>(null);
  const [searchResult, setSearchResult] = useState("");
  const [searchResult2, setSearchResult2] = useState(0);

  useEffect(() => {
    setSearchResult(query);
  }, [query]);

  useEffect(() => {
    if (ref.current) {
      ref.current?.focus();
    } else {
      setSearchResult2(searchResult2 + 1);
    }
  }, [searchResult2]);


  return (
    <>
      <Modal
        isOpen={openDialog}
        role="dialog"
        autoFocus={true}
        centered={true}
        size="lg"
        query={query}
        className="exampleModal"
        // @ts-ignore
        tabIndex="-1"
        toggle={toggle}
      >
        <div className="modal-content">
          <ModalHeader
            toggle={toggle}
            className="ett-bg-secondary text-blue m-0"
          >
            <span className="mx-4">Download</span>
          </ModalHeader>
          <div className="px-5 mt-2"></div>
          <Form
            onSubmit={(e) => {
              e.preventDefault();
              //validation.handleSubmit(e)
              return false;
            }}
          >
            <ModalBody className="">
              <div className="row">
                <div className="col-lg">
                  <div className="custom-shadow px-5">
                    <input
                      ref={ref}
                      type="text"
                      value={searchResult}
                      onChange={(e) => setSearchResult(e.target.value)}
                    />
                  </div>
                </div>
              </div>
            </ModalBody>
          </Form>
        </div>
      </Modal>
    </>
  );
};

May I know how can I achieve this.??

4

Answers


  1. Try putting this file instead of yours in the sandbox

    import axios from "axios";
    import React, { useEffect, useLayoutEffect, useState, useRef } 
    from "react";
    import {
      Button,
      Col,
      Form,
      Modal,
      ModalBody,
      ModalHeader,
      Row
    } from "reactstrap";
    
    const Dialog = ({ openDialog, query, toggle }: any) => {
      const ref = useRef<HTMLInputElement | null>(null);
      const [searchResult, setSearchResult] = useState("");
      const [searchResult2, setSearchResult2] = useState(0);
    
      useEffect(() => {
        setSearchResult(query);
      }, [query]);
    
      useEffect(() => {
        if (ref.current) {
          ref.current?.focus();
        } else {
          setSearchResult2(searchResult2 + 1);
        }
      }, [searchResult2]);
    
      return (
        <>
          <Modal
            isOpen={openDialog}
            role="dialog"
            autoFocus={true}
            centered={true}
            size="lg"
            query={query}
            className="exampleModal"
            // @ts-ignore
            tabIndex="-1"
            toggle={toggle}
          >
            <div className="modal-content">
              <ModalHeader
                toggle={toggle}
                className="ett-bg-secondary text-blue m-0"
              >
                <span className="mx-4">Download</span>
              </ModalHeader>
              <div className="px-5 mt-2"></div>
              <Form
                onSubmit={(e) => {
                  e.preventDefault();
                  //validation.handleSubmit(e)
                  return false;
                }}
              >
                <ModalBody className="">
                  <div className="row">
                    <div className="col-lg">
                      <div className="custom-shadow px-5">
                        <input
                          ref={ref}
                          type="text"
                          value={searchResult}
                          onChange={(e) => setSearchResult(e.target.value)}
                        />
                      </div>
                    </div>
                  </div>
                </ModalBody>
              </Form>
            </div>
          </Modal>
        </>
      );
    };
    export default Dialog;
    
    Login or Signup to reply.
  2. You can do something like that

    const fieldOne = useRef(null);
    
    useEffect(() => {
        if (fieldOne.current && openDialog && document.activeElement !== fieldOne.current) {
          fieldOne.current.focus();
        }
    })
    

    And here is demo https://codesandbox.io/s/modal-reactstrap-forked-jomb3d?file=/src/modal.tsx:317-350

    Login or Signup to reply.
  3. You can do it like this:

     useEffect(() => {
        if (ref.current) {
          ref.current?.focus();
          if (searchResult?.length < 1) {
            setDialog({ value: "", isModalOpen: false });
          }
        }
      }, [searchResult]);
    
    

    Do not forget to include setDialog in the props. Here a working sandbox.

    Login or Signup to reply.
  4. You can make use of the Modal’s onOpened Prop:

    <Modal
      isOpen={openDialog}
      onOpened={onOpened}
      role="dialog"
      autoFocus={true}
      centered={true}
      size="lg"
      query={query}
      className="exampleModal"
      // @ts-ignore
      tabIndex="-1"
      toggle={toggle}
    >
    

    then focus the reference:

    const onOpened = () => {
      // consider adding a check that ref.current !== null
      ref.current.focus();
    }
    

    here’s your sandbox edited with those changes, it focuses onOpen. I don’t know the second part of your problem is, and what you are trying to to do when you leave the modal. But you could use the Modal’s onClosed prop and use a callback from the parent.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search