Estoy implementando una funcionalidad compleja de autocompletar, y el punto es que cuando la entrada se enfoca, debo mostrar el cuadro de resultados, y cuando el usuario va a la siguiente entrada o hace clic en cualquier parte de la pantalla, o presiona Escape, entonces debo cerrar el cuadro de resultados.
Para cerrar el cuadro de resultados, estoy usando el evento onBlur .
El problema es que dentro del cuadro de resultados tengo un botón que lleva al usuario a un cuadro de diálogo de búsqueda más completo, pero cuando hago clic en él, se activa el evento onBlur y evita que se haga clic en este botón.
Aquí está mi código:
import { useState } from "react"; export default function IndexPage() { const [isOpen, setIsOpen] = useState(false); const [text, setText] = useState(""); return ( <div> <input onBlur={() => setIsOpen(false)} onFocus={() => setIsOpen(true)} /> {isOpen && ( <div> something <br /> <button onClick={() => setText("i am clicked")}>click me</button> </div> )} <br /> <input /> <br /> <p>{text}</p> </div> ); }¿Cómo puedo hacer que funcione correctamente?
Puedes ver un ejemplo en vivo en este codesandbox
Estoy usando Next.js
En primer lugar, debe agrupar input y el button para tener un área de enfoque más amplia. Estoy usando div para ese propósito, pero onBlur y onFocus no se aplican para un div habitual, por lo que debemos tener tabIndex="1" , que es para que ese elemento sea interactivo con esos eventos.
<div tabIndex="1" onBlur={() => setIsOpen(false)} onFocus={() => setIsOpen(true)} > </div> En segundo lugar, debemos usar el evento onMouseDown en lugar de onClick , que es para evitar enfocar el estado en el elemento del button .
<button onMouseDown={() => setText("i am clicked")}> click me </button>La implementación completa puede ser ( https://codesandbox.io/s/strange-violet-z0u3jr )
import { useState } from "react"; export default function IndexPage() { const [isOpen, setIsOpen] = useState(false); const [text, setText] = useState(""); return ( <div> <div tabIndex="1" onBlur={() => setIsOpen(false)} onFocus={() => setIsOpen(true)} > <input /> {isOpen && ( <div> something <br /> <button onMouseDown={() => setText("i am clicked")}> click me </button> </div> )} </div> <br /> <input /> <br /> <p>{text}</p> </div> ); }