I have a Code Sandbox here that demonstrates what I want to do.
When the user presses a button, a text input is revealed and is given focus.
To do this, I use a ref and give it focus, which is fine:
//When user clicks button, show input
const handleClick = useCallback(() => {
setShowInput(true);
}, []);
useEffect(() => {
if (showInput && inputRef.current) {
inputRef.current.focus();
}
}, [showInput]);
When the user tabs out of the text field, I want the focus to be back on that button.
In the code I have here, I achieve this also by using a ref and giving focus to the button.
//When user exits input, unshow input
//Also, need to tab to button if it was a tab button press.
const handleInputBlur = useCallback(() => {
setShowInput(false);
if (buttonRef.current) {
buttonRef.current.focus();
}
}, []);
However, the problem is if the user instead uses their mouse to click say, the other button, then focus is still given to the trigger button.
What I'd like to be able to do is define some tab order for these components, that would be:
TextField => Trigger Button => Other Button
However, I don't want to hard code tab indexes into my component, as that would likely not play well with the application as a whole?
Is there an elegant react solution to this?
The best answer here is that if you want your tab order to be TextField => Trigger Button => Other Button, then have the HTML render in that order.
You can then use CSS to change the visual ordering.
.container {
display: flex;
border: solid 1px black;
}
button {
margin: 1em;
padding: 1em;
}
.order-1 {
order: 1;
}
.order-2 {
order: 2;
}
.order-3 {
order: 3;
}
.order-4 {
order: 4;
}
<div class = "container">
<button class ="order-4"> 1</button>
<button class = "order-2"> 2</button>
<button class = "order-3"> 3</button>
<button class ="order-1"> 4</button>
</div>