fix: enhance accessibility in SingleDatePicker by adding roles and improving aria-labels

This commit is contained in:
Astrian Zheng 2025-02-19 22:07:03 +11:00
parent 7b20bcbf14
commit 44ace7cddb
Signed by: Astrian
SSH Key Fingerprint: SHA256:rVnhx3DAKjujCwWE13aDl7uV6+9U1MvydLkNRXJrBiA

View File

@ -79,53 +79,57 @@ export default ({ value, onSelect, localization }: Props) => {
else setCurrentMonth(currentMonth + 1) else setCurrentMonth(currentMonth + 1)
} }
if (selectMonth) return (<div className='datenel-component' aria-label="Date picker, you are now at month and year quick-select panel"> if (selectMonth) return (
<div className='header'> <div className='datenel-component' role="dialog" aria-label="Date selection panel, you are now at month and year quick-select">
<button className='stepper' onClick={() => { <div className='header'>
if (currentYear === 0) return <button className='stepper' onClick={() => {
setCurrentYear(currentYear - 1) if (currentYear === 0) return
}} aria-label={`Go to last year, ${currentYear - 1}, you are now at year ${currentYear}`}><img src={LeftArrowIcon} /></button> setCurrentYear(currentYear - 1)
<input className='indicator' }} aria-label={`Go to last year, ${currentYear - 1}, you are now at year ${currentYear}`}><img src={LeftArrowIcon} /></button>
value={currentYear} <input className='indicator'
onChange={e => setCurrentYear(parseInt(e.target.value))} value={currentYear}
aria-label="Year input, type a year to go to that year" onChange={e => setCurrentYear(parseInt(e.target.value))}
/> aria-label="Year input, type a year to go to that year"
<button className='stepper' onClick={() => { />
if (currentYear === 9999) return <button className='stepper' onClick={() => {
setCurrentYear(currentYear + 1) if (currentYear === 9999) return
}} aria-label={`Go to next year, ${currentYear + 1}, you are now at year ${currentYear}`}><img src={RightArrowIcon} /></button> setCurrentYear(currentYear + 1)
}} aria-label={`Go to next year, ${currentYear + 1}, you are now at year ${currentYear}`}><img src={RightArrowIcon} /></button>
</div>
<div className='month-selector-body'>
{Array.from({ length: 12 }).map((_, index) => <button className={`item`} key={index} onClick={() => {
setCurrentMonth(index)
setSelectMonth(false)
}} aria-label={`Go to ${new Date(currentYear, index).toLocaleString(localization || navigator.language, { month: 'long' })} of the year ${currentYear}`}>
{new Date(currentYear, index).toLocaleString(localization || navigator.language, { month: 'long' })}
</button>)}
</div>
</div> </div>
<div className='month-selector-body'> )
{Array.from({ length: 12 }).map((_, index) => <button className={`item`} key={index} onClick={() => { else return (
setCurrentMonth(index) <div className='datenel-component' role="dialog" aria-label="Date selection panel">
setSelectMonth(false) <div className='header'>
}} aria-label={`Go to ${new Date(currentYear, index).toLocaleString(localization || navigator.language, { month: 'long' })} of the year ${currentYear}`}> <button className='stepper' onClick={skipToLastMonth} aria-label={`Go to last month, ${new Date(currentYear, currentMonth - 1).toLocaleString(localization || navigator.language, { month: 'long' })}`}><img src={LeftArrowIcon} /></button>
{new Date(currentYear, index).toLocaleString(localization || navigator.language, { month: 'long' })} <button className='indicator' onClick={() => setSelectMonth(true)} aria-label={`You are now at ${new Date(currentYear, currentMonth).toLocaleString(localization || navigator.language, { month: 'long', year: 'numeric' })}. Click here to quick-select month or year.`}>
</button>)} {new Date(currentYear, currentMonth).toLocaleString(localization || navigator.language, { month: 'long', year: 'numeric' })}
</div> </button>
</div>) <button className='stepper' onClick={skipToNextMonth} aria-label={`Go to next month, ${new Date(currentYear, currentMonth + 1).toLocaleString(localization || navigator.language, { month: 'long' })}`}><img src={RightArrowIcon} /></button>
else return (<div className='datenel-component' aria-label="Date picker. Click Tab button to switch between months, or select a date"> </div>
<div className='header'> <div className='calendar-view-body' aria-live="polite">
<button className='stepper' onClick={skipToLastMonth} aria-label={`Go to last month, ${new Date(currentYear, currentMonth - 1).toLocaleString(localization || navigator.language, { month: 'long' })}`}><img src={LeftArrowIcon} /></button> {l10nDays.map((day, index) => <div className='item day-indicator' key={index}>{day}</div>)}
<button className='indicator' onClick={() => setSelectMonth(true)} aria-label={`You are now at ${new Date(currentYear, currentMonth).toLocaleString(localization || navigator.language, { month: 'long', year: 'numeric' })}. Click here to quick-select month or year.`}>
{new Date(currentYear, currentMonth).toLocaleString(localization || navigator.language, { month: 'long', year: 'numeric' })}
</button>
<button className='stepper' onClick={skipToNextMonth} aria-label={`Go to next month, ${new Date(currentYear, currentMonth + 1).toLocaleString(localization || navigator.language, { month: 'long' })}`}><img src={RightArrowIcon} /></button>
</div>
<div className='calendar-view-body'>
{l10nDays.map((day, index) => <div className='item day-indicator' key={index}>{day}</div>)}
{dates.map(date => <button {dates.map(date => <button
className={`item date ${currentMonth !== date.getMonth() && 'extra-month'} ${selectedDate.toDateString() === date.toDateString() && 'active'}`} className={`item date ${currentMonth !== date.getMonth() && 'extra-month'} ${selectedDate.toDateString() === date.toDateString() && 'active'}`}
key={date.toISOString()} key={date.toISOString()}
onClick={() => selectDate(date)} onClick={() => selectDate(date)}
aria-label={`${date.toLocaleString(localization || navigator.language, { dateStyle: 'full' })}${date.toDateString() === new Date().toDateString() ? ", this is today" : ""}, click to select this date`} aria-label={`${date.toLocaleString(localization || navigator.language, { dateStyle: 'full' })}${date.toDateString() === new Date().toDateString() ? ", this is today" : ""}, click to select this date`}
tabIndex={currentMonth !== date.getMonth() ? -1 : 0 } tabIndex={currentMonth !== date.getMonth() ? -1 : 0}
aria-hidden={currentMonth !== date.getMonth()} aria-hidden={currentMonth !== date.getMonth()}
> >
{date.getDate()} {date.getDate()}
{date.toDateString() === new Date().toDateString() && <svg xmlns="http://www.w3.org/2000/svg" className='today-indicator' viewBox="0 0 24 24" fill="currentColor"><path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"></path></svg>} {date.toDateString() === new Date().toDateString() && <svg xmlns="http://www.w3.org/2000/svg" className='today-indicator' viewBox="0 0 24 24" fill="currentColor"><path d="M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z"></path></svg>}
</button>)} </button>)}
</div>
</div> </div>
</div>) )
} }