This is my code
import React, { useState, useRef } from "react";
const alphabet = ["A", "B", "C", "D", "E"];
export default function App() {
const [selected, setSelected] = useState<number | null>(null);
const selectedRef = useRef<HTMLDivElement>(null);
const selectLetter = (i: number) => {
if (selected === i) {
setSelected(null);
} else {
setSelected(i);
}
};
const navigate = (
event: React.KeyboardEvent<HTMLDivElement>,
letter: string,
i: number
) => {
if (event.key === "Enter") {
if (i === selected) {
setSelected(null);
} else {
setSelected(i);
}
}
};
return (
<div
tabIndex={-1}
style={{
display: "flex",
gap: "5px",
flexWrap: "wrap"
}}
>
{alphabet.map((letter: string, i: number) => (
<div
ref={selected === i ? selectedRef : null}
onClick={() => selectLetter(i)}
onKeyDown={(event) => navigate(event, letter, i)}
tabIndex={selected === i ? 0 : -1}
style={{
border: "1px solid blue",
padding: "30px",
backgroundColor: i === selected ? "blue" : "white",
color: i === selected ? "white" : "black",
fontWeight: "bolder",
cursor: "pointer"
}}
>
{letter}
</div>
))}
</div>
);
}
I have the letters "A", "B", "C", "D", "E". If I click them, then they get highlighted. Only one letter can be selected at a time and it could be deselected if you click them again. That part works fine.
The part I'm having trouble with is integrating keyboard to work too.
I also want to be able to use my keyboard and do the same thing but instead with keyboard. Like lets say by default the tabIndex is on "A". if I press enter it would highlight "A"
If I press enter again (deselects 'A')
I should also be able to use arrow key to move the tabIndex, so for example if I use the right key then it would be focused on "B". And then when I press enter, then B should be highlighted
I should freely be able to navigate A,B,C,D,E with my keyboard.
I'm reading the tabindex article in mozilla and I just cant figure it out. I somewhat have the enter working but after one press I'm unsure how to get the tabindex to move.
myplayground: https://codesandbox.io/s/clever-aryabhata-vxoi90?file=/src/App.tsx:0-1358
CodePudding user response:
First, you want your tabIndex
be 0
for all elements so you can navigate through them in sequential order with the Tab
key. That's the only purpose of the tabIndex
attribute here.
Then, for navigating through arrow keys you can check for the ArrowLeft
/ ArrowRight
event.key
, and then .focus()
the previous / next element:
if (event.key === "ArrowLeft") {
document.querySelectorAll("#root div div")[i-1]?.focus();
}
if (event.key === "ArrowRight") {
document.querySelectorAll("#root div div")[i 1]?.focus();
}
Here's your updated codesandbox: https://codesandbox.io/s/empty-tdd-8g3prn?file=/src/App.tsx