I have a search input component in React, which also has a lot of options. I want the options box to appear when the input is focused, or while there's interaction in the box. This box should disappear when something outside of either search input of the box is being focused. So, it behaves like a pretty standard behavior.
There is a problem that I'm not sure how to solve. Some of the actions inside the options box cause another component to be rendered inside the box, so the focus is being lost (the browser focuses the <body>). My component thinks that it means to hide the options box.
I found a fix for that - I only hide the box if the blur of the container was caused by something from outside of it. It works correctly in some cases. But there's a problem when, let's say, there's a button causing the options box to render something else, making the button itself disappear. The focus goes to the <body> and I can no longer hide the options box without manually focusing on the search input and then focusing out.
Are there some techniques to manage visibility per real or pseudo focus? In perfect scenario, I'd like to avoid programatically focusing my element in, for two reasons:
autofocus attribute to work correctly.For simplicity, I removed the props and elements irrelevant to the question. But there's quite a bit going on for the <OptionsBox />.
Here's my simplified component:
import { useState } from 'react';
import OptionsBox from './OptionsBox';
export default function Search() {
const [value, setValue] = useState('');
const [showOptions, setShowOptions] = useState(false);
return (
<div
tabIndex={-1}
onFocus={() => setShowOptions(true)}
onBlur={event => {
const isChildFocused = event.currentTarget.contains(event.relatedTarget);
if (!isChildFocused) {
setShowOptions(false);
}
}}
>
<input
type="text"
value={value}
onChange={event => setValue(event.target.value)}
/>
{showOptions && (
<OptionsBox />
)}
</div>
);
}
I tried to get some workaround to work on this issue and find it this way (in the link).
Autofocus parent wrapper (depends on requirement).track the click event. If it is inside, then keep the focus else, blur the <OptionBox />ref to parentDiv and passed it to <OptionBox/> for tracking2 buttons for testing onClick focus events
1st onCLick for focusing body2nd onClick to focus input within <Parent/> / <OptionBox/>clickHandler to check, if the element you are trying to focus on is within parentDiv, if so, then keep the focus else blur it and setState to false.Not sure about the Efficiency of this solution but you can try this (if already haven't tried it) as it totally depends on the use case.
Link: https://codesandbox.io/s/youthful-hypatia-4mu2x?file=/src/OptionBox.js