If the user selected a date, we want to focus on that date. Once they have their attention on a date, the next up/down/left/right movement would make sense.
If the user has selected a date, there would be a <button> with an is-selected class.
We will also use a return statement here to prevent further execution of the function.
Let’s say the user selects 13 February. If they press the right arrow now, we want to highlight 14 February.
To do this, need to find 14 February. To find 14 February, we need to get the index of the selected date.
datepicker.addEventListener('keydown', event => {
// ...
const index = dates.findIndex(d => d === selectedDate)
if (key === 'ArrowRight') {
const nextDate = dates[index + 1]
nextDate.focus()
}
})
We’ve done all we need by now. So we’ll use a return statement here to prevent the function from executing further. This makes it easier to write other conditionals.
Let’s say the user presses the right arrow key when their focus is on 14 February. In this case, we want to select 15 February. To do this, we need to use the index of the currently focused date (instead of the selected date).
datepicker.addEventListener('keydown', event => {
// ...
let index = dates.findIndex(d => d === selectedDate)
const focusedDate = document.activeElement
if (focusedDate.matches('.datepicker__date')) {
index = dates.findIndex(d => d === focusedDate))
}
if (key === 'ArrowRight') return dates[index + 1].focus()
})
We can clean up the code a little by using a ternary operator.
datepicker.addEventListener('keydown', event => {
// ...
const index = document.activeElement.matches('.datepicker__date')
? dates.findIndex(d => d === document.activeElement)
: dates.findIndex(d => d === selectedDate)
// ...
})
We also need to allow the code to reach this point. So, if the user has focus on a date (but did not select a date yet), we don’t force focus onto the first date.
Let’s say the user press the Right arrow key when their focus is on the last day (28 February). In this case, we want to highlight the first day of the next month (1 March).
Here, we first need to check if they are on the last day. We’ll use another if condition for the checking. We will also put the new if condition before the previous if condition because it’s more specific.
datepicker.addEventListener('keydown', event => {
// ...
if (key === 'ArrowRight' && index === dates.length - 1) {
// ... Highlight first day of the next month
}
if (key === 'ArrowRight') /*...*/
})
To focus on the next month, we need to change the calendar such that it shows the next month. We can do it by clicking the next month’s button.
If the user presses Up, we want to focus on the previous week. Since one week is 7 days, we can subtract 7 from the index to find the previous week’s date.
If the index is small than 7, we know the user is on the first week of the month. In this case, we need to select the date that’s on the last week of the previous month.
Let’s say the user has focus on 6 February 2019. If they press up, we want to focus on 30 January 2019.
First, we need to show the previous month by clicking on the previous month’s button.
datepicker.addEventListener('keydown', event => {
// ...
if (key === 'ArrowUp' && index < 7) {
previousMonthButton.click()
}
if (key === 'ArrowUp') /*...*/
})
Then, we need to find the new set of dates.
datepicker.addEventListener('keydown', event => {
// ...
if (key === 'ArrowUp' && index < 7) {
previousMonthButton.click()
const dates = [...datepicker.querySelectorAll('.datepicker__date')]
}
if (key === 'ArrowUp') /*...*/
})
Then, we need to do some math to get the correct date to focus on.
If index is 6, we want the last day of the previous month
If index is 5, we want the 2nd last day of the previous month
If index is 4, we want the 3rd last day of the previous month
And so on.
We can do it with this calculation: dates.length - (7 - index).
If index + 7 is more than the number of days in the month, we know the user is pressing Down from the last week. In this case, we need to focus on the next week in the next month.
Let’s say the user presses Down from 27 February 2019. In this case, we want to focus on 6 March 2019.
First, we need to show the next month by clicking on the next month’s button.