Skip to content

Commit

Permalink
Address accessibility issues
Browse files Browse the repository at this point in the history
 * Side nav aria-label removed so the complete entry is read by screen
readers
 * DatePicker has more helpful text announced by screen readers
 * Duration label is clearer
 * Save noticiation message is more generic and the whole message is
read instead of just the updated date/time
 * Goal selector no longer eats tabs and can be navigated out of by a
keyboard
 * Skip nav link placed on top of header when focused
  • Loading branch information
jasalisbury committed Mar 4, 2021
1 parent 5426898 commit edccb36
Show file tree
Hide file tree
Showing 8 changed files with 43 additions and 26 deletions.
4 changes: 4 additions & 0 deletions frontend/src/App.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
.usa-skipnav:focus {
z-index: 999999;
}

.smart-hub-offset-nav {
margin-left: 8rem;
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/DatePicker.css
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
with the tab key. Since the open button has tabindex of -1
we won't run into an issue of focus moving "backwards"
*/
flex-direction: row-reverse;
/* flex-direction: row-reverse; */
width: fit-content;
}

Expand Down
21 changes: 17 additions & 4 deletions frontend/src/components/DatePicker.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import './DatePicker.css';
const dateFmt = 'MM/DD/YYYY';

const DateInput = ({
control, minDate, name, disabled, maxDate, openUp, required,
control, minDate, name, disabled, maxDate, openUp, required, ariaName,
}) => {
const hintId = `${name}-hint`;
const [isFocused, updateFocus] = useState(false);
Expand All @@ -43,22 +43,34 @@ const DateInput = ({
const date = value ? moment(value, dateFmt) : null;
return (
<div className="display-flex smart-hub--date-picker-input">
<button onClick={() => { updateFocus(true); }} disabled={disabled} tabIndex={-1} aria-label="open calendar" type="button" className="usa-date-picker__button margin-top-0" />
<SingleDatePicker
id={name}
ariaLabel={`${ariaName}, month/day/year, edit text`}
placeholder={null}
focused={isFocused}
date={date}
ref={ref}
isOutsideRange={isOutsideRange}
numberOfMonths={1}
openDirection={openDirection}
disabled={disabled}
hideKeyboardShortcutsPanel
onDateChange={(d) => {
const newDate = d ? d.format(dateFmt) : d;
onChange(newDate);
}}
onFocusChange={({ focused }) => updateFocus(focused)}
hideKeyboardShortcutsPanel
onFocusChange={({ focused }) => {
if (!focused) {
updateFocus(focused);
}
}}
/>
<button
onClick={() => { updateFocus(true); }}
disabled={disabled}
aria-label={`${ariaName} open calendar"`}
type="button"
className="usa-date-picker__button margin-top-0"
/>
</div>
);
Expand All @@ -80,6 +92,7 @@ DateInput.propTypes = {
// eslint-disable-next-line react/forbid-prop-types
control: PropTypes.object.isRequired,
name: PropTypes.string.isRequired,
ariaName: PropTypes.string.isRequired,
minDate: PropTypes.string,
maxDate: PropTypes.string,
openUp: PropTypes.bool,
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/MultiSelect.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ function MultiSelect({
components={{ ...componentReplacements, DropdownIndicator }}
options={options}
isDisabled={disabled}
tabSelectsValue={false}
isClearable={multiSelectOptions.isClearable}
closeMenuOnSelect={multiSelectOptions.closeMenuOnSelect}
controlShouldRenderValue={multiSelectOptions.controlShouldRenderValue}
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/Navigator/components/SideNav.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ function SideNav({
unstyled
className={`smart-hub--navigator-link ${page.current ? 'smart-hub--navigator-link-active' : ''}`}
role="button"
aria-label={page.label}
>
<span className="margin-left-2">{page.label}</span>
<span className="margin-left-auto margin-right-2">
Expand Down Expand Up @@ -79,8 +78,8 @@ function SideNav({
)}
{lastSaveTime && !errorMessage
&& (
<Alert aria-live="polite" type="success" slim noIcon className="smart-hub--save-alert">
This report was automatically saved on
<Alert aria-atomic aria-live="polite" type="success" slim noIcon className="smart-hub--save-alert">
This report was last saved on
{' '}
{lastSaveTime.format('MM/DD/YYYY [at] h:mm a')}
</Alert>
Expand Down
14 changes: 8 additions & 6 deletions frontend/src/components/Navigator/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,6 @@ function Navigator({
const { isDirty, errors, isValid } = formState;
const hasErrors = Object.keys(errors).length > 0;

useEffect(() => {
if (showValidationErrors && !page.review) {
trigger();
}
}, [page.review, trigger, showValidationErrors]);

const newNavigatorState = () => {
if (page.review) {
return pageState;
Expand Down Expand Up @@ -124,6 +118,14 @@ function Navigator({
reset(formData);
}, [currentPage, reset, formData]);

useEffect(() => {
if (showValidationErrors && !page.review) {
setTimeout(() => {
trigger();
});
}
}, [page.path, page.review, trigger, showValidationErrors]);

const navigatorPages = pages.map((p) => {
const current = p.position === page.position;

Expand Down
4 changes: 3 additions & 1 deletion frontend/src/pages/ActivityReport/Pages/activitySummary.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ const ActivitySummary = ({
name="startDate"
>
<DatePicker
ariaName="Start Date (Required)"
control={control}
maxDate={endDate}
name="startDate"
Expand All @@ -241,6 +242,7 @@ const ActivitySummary = ({
name="endDate"
>
<DatePicker
ariaName="End Date (required)"
control={control}
minDate={startDate}
disabled={!startDate}
Expand All @@ -251,7 +253,7 @@ const ActivitySummary = ({
</Grid>
<Grid col={5}>
<FormItem
label="Duration"
label="Duration in hours"
name="duration"
>
<TextInput
Expand Down
18 changes: 7 additions & 11 deletions frontend/src/pages/ActivityReport/Pages/goalsObjectives.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ const GoalsObjectives = ({
register,
} = useFormContext();
const [availableGoals, updateAvailableGoals] = useState([]);
const [loading, updateLoading] = useState(true);
const hasGrants = grantIds.length > 0;

useDeepCompareEffect(() => {
Expand All @@ -27,25 +26,18 @@ const GoalsObjectives = ({
const fetchedGoals = await getGoals(grantIds);
updateAvailableGoals(fetchedGoals);
}
updateLoading(false);
};
fetch();
}, [grantIds]);

if (loading) {
return (
<div>
loading...
</div>
);
}
const showGoals = activityRecipientType === 'grantee' && hasGrants;

return (
<>
<Helmet>
<title>Goals and objectives</title>
</Helmet>
{activityRecipientType === 'grantee' && hasGrants
{showGoals
&& (
<Fieldset className="smart-hub--report-legend smart-hub--form-section" legend="Goals and objectives">
<div id="goals-and-objectives" />
Expand All @@ -56,7 +48,11 @@ const GoalsObjectives = ({
)}
<Fieldset className="smart-hub--report-legend smart-hub--form-section" legend="Context">
<Label htmlFor="context">OPTIONAL: Provide background or context for this activity</Label>
<Textarea id="context" name="context" inputRef={register()} />
<Textarea
id="context"
name="context"
inputRef={register()}
/>
</Fieldset>
</>
);
Expand Down

0 comments on commit edccb36

Please sign in to comment.