iPapatsoris
iPapatsoris

Reputation: 23

Focus on inner input with onMouseDown on container

I have an input which is contained within a wrapper div. On mousedown on the wrapper, I want the inner input to take focus.

import "./styles.css";
import { useRef } from "react";

export default () => {
  const ref = useRef(null);

  return (
    <div className="App">
      <div
        className="Wrapper"
        onMouseDown={(e) => {
          ref.current.focus();
          // e.preventDefault();
        }}
      >
        <input ref={ref} />
      </div>
    </div>
  );
};

However, focus does not work, unless I include e.preventDefault(). But the problem with this approach is that it disables text highlighting on the input, which seems to be a default behavior for mouse down, so it's undesirable. On the other hand, if I use onClick instead of onMouseDown, it works fine even without preventing default, but I would like to focus on onMouseDown.

Why is this happening, and what is the best way to solve it?

Live demo

Edit old-star-ql689t

Upvotes: 0

Views: 56

Answers (1)

Saad
Saad

Reputation: 36

This happens because as soon as you click in the container, the callback fires. And the input is focused, but then the default handler executes and blurs the input. Now, one way is to use setTimeout - to delay the focus() call. So that, the element.focus() runs after browser's default handler execution.

    (e) => {
        setTimeout(()=>ref.current.focus(), 100)
    }

Another way is to stopPropagation from the input element and then preventDefault in the wrapper.

export default () => {
  const ref = useRef(null);
  return (
    <div className="App">
      <div
        className="Wrapper"
        onMouseDown={(e) => {
          ref.current.focus();
          e.preventDefault();
        }}
      >
        <input ref={ref} onMouseDown={(e) => {
          e.stopPropagation();
        }}/>
      </div>
    </div>
  );
};

Edit event-execution-delay

Upvotes: 1

Related Questions