Skip to content

Commit

Permalink
a11y: accessibility issue 2026 (#2740)
Browse files Browse the repository at this point in the history
* allow accessing table cells and associate them with table header

* add aria-label

* fix unit test

Co-authored-by: Ben Yackley <61990921+beyackle@users.noreply.github.com>
Co-authored-by: Chris Whitten <christopher.whitten@microsoft.com>
  • Loading branch information
3 people committed Apr 24, 2020
1 parent db3fda7 commit 0ac036f
Show file tree
Hide file tree
Showing 10 changed files with 157 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('<Home/>', () => {
);
expect(container).toHaveTextContent('a');
expect(container).toHaveTextContent('b');
const link = queryByLabelText('a');
const link = queryByLabelText('Bot name is a');
fireEvent.dblClick(link);
expect(onItemChosen.mock.results[0].value).toBe('path1');
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { styles as wizardStyles } from '../StepWizard/styles';
import { StorageFolder, File } from '../../store/types';
import { getFileIconName, calculateTimeDiff } from '../../utils';

import { dropdown, detailListContainer, detailListClass } from './styles';
import { dropdown, detailListContainer, detailListClass, tableCell, content } from './styles';

interface FileSelectorProps {
operationMode: {
Expand Down Expand Up @@ -61,7 +61,13 @@ const _renderIcon = (file: File) => {

const _renderNameColumn = (file: File) => {
const iconName = getFileIconName(file);
return <span aria-label={`${iconName} Name is ${file.name}`}>{file.name}</span>;
return (
<div data-is-focusable={true} css={tableCell}>
<div tabIndex={-1} css={content} aria-label={`${iconName} Name is ${file.name}`}>
{file.name}
</div>
</div>
);
};

export const FileSelector: React.FC<FileSelectorProps> = props => {
Expand Down Expand Up @@ -107,9 +113,15 @@ export const FileSelector: React.FC<FileSelectorProps> = props => {
data: 'number',
onRender: (item: File) => {
return (
<span aria-label={`Last modified time is ${calculateTimeDiff(item.lastModified)}`}>
{calculateTimeDiff(item.lastModified)}
</span>
<div css={tableCell} data-is-focusable={true}>
<div
tabIndex={-1}
css={content}
aria-label={formatMessage(`Last modified time is {time}`, { time: calculateTimeDiff(item.lastModified) })}
>
{calculateTimeDiff(item.lastModified)}
</div>
</div>
);
},
isPadded: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,14 @@ export const detailListClass = mergeStyleSets({
maxWidth: '16px',
},
});

export const tableCell = css`
outline: none;
:focus {
outline: rgb(102, 102, 102) solid 1px;
}
`;

export const content = css`
outline: none;
`;
26 changes: 23 additions & 3 deletions Composer/packages/client/src/pages/home/RecentBotList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import formatMessage from 'format-message';

import { calculateTimeDiff } from '../../utils';

import { detailListContainer } from './styles';
import { detailListContainer, tableCell, content } from './styles';

interface RecentBotListProps {
onItemChosen: (file: IObjectWithKey) => void;
Expand All @@ -42,7 +42,17 @@ export function RecentBotList(props: RecentBotListProps): JSX.Element {
sortDescendingAriaLabel: formatMessage('Sorted Z to A'),
data: 'string',
onRender: item => {
return <span aria-label={item.name}>{item.name}</span>;
return (
<div css={tableCell} data-is-focusable={true}>
<div
tabIndex={-1}
css={content}
aria-label={formatMessage(`Bot name is {botName}`, { botName: item.name })}
>
{item.name}
</div>
</div>
);
},
isPadded: true,
},
Expand All @@ -55,7 +65,17 @@ export function RecentBotList(props: RecentBotListProps): JSX.Element {
isResizable: true,
data: 'number',
onRender: item => {
return <span>{calculateTimeDiff(item.dateModified)}</span>;
return (
<div css={tableCell} data-is-focusable={true}>
<div
tabIndex={-1}
css={content}
aria-label={formatMessage(`Last modified time is {time}`, { time: calculateTimeDiff(item.dateModified) })}
>
{calculateTimeDiff(item.dateModified)}
</div>
</div>
);
},
isPadded: true,
},
Expand Down
12 changes: 12 additions & 0 deletions Composer/packages/client/src/pages/home/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,3 +253,15 @@ export const exampleListCellDescription = css`
font-size: ${fonts.small.fontSize};
color: ${palette.neutralTertiary};
`;

export const tableCell = css`
outline: none;
width: auto;
:focus {
outline: rgb(102, 102, 102) solid 1px;
}
`;

export const content = css`
outline: none;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { LgTemplate } from '@bfc/shared';
import { StoreContext } from '../../store';
import { increaseNameUtilNotExist } from '../../utils/lgUtil';
import { navigateTo } from '../../utils';
import { actionButton, formCell } from '../language-understanding/styles';
import { actionButton, formCell, content } from '../language-understanding/styles';

interface TableViewProps extends RouteComponentProps<{}> {
dialogId: string;
Expand Down Expand Up @@ -144,7 +144,9 @@ const TableView: React.FC<TableViewProps> = props => {
onRender: item => {
return (
<div data-is-focusable={true} css={formCell}>
#{item.name}
<div tabIndex={-1} css={content} aria-label={formatMessage(`Name is {name}`, { name: item.name })}>
#{item.name}
</div>
</div>
);
},
Expand All @@ -160,7 +162,13 @@ const TableView: React.FC<TableViewProps> = props => {
onRender: item => {
return (
<div data-is-focusable={true} css={formCell}>
{item.body}
<div
tabIndex={-1}
css={content}
aria-label={formatMessage(`Response is {response}`, { response: item.body })}
>
{item.body}
</div>
</div>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,14 @@ export const consoleStyle = css`
padding: 15px;
margin-bottom: 20px;
`;

export const tableCell = css`
outline: none;
:focus {
outline: rgb(102, 102, 102) solid 1px;
}
`;

export const content = css`
outline: none;
`;
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { LuFile } from '@bfc/shared';
import { StoreContext } from '../../store';
import { navigateTo } from '../../utils';

import { formCell, luPhraseCell } from './styles';
import { formCell, luPhraseCell, tableCell, content } from './styles';
interface TableViewProps extends RouteComponentProps<{}> {
dialogId: string;
}
Expand Down Expand Up @@ -117,7 +117,9 @@ const TableView: React.FC<TableViewProps> = props => {
}
return (
<div data-is-focusable={true} css={formCell}>
{displayName}
<div tabIndex={-1} css={content} aria-label={formatMessage(`Name is {name}`, { name: displayName })}>
{displayName}
</div>
</div>
);
},
Expand All @@ -133,7 +135,13 @@ const TableView: React.FC<TableViewProps> = props => {
onRender: item => {
return (
<div data-is-focusable={true} css={luPhraseCell}>
{item.phrases}
<div
tabIndex={-1}
css={content}
aria-label={formatMessage(`Sample Phrases are {phrases}`, { phrases: item.phrases })}
>
{item.phrases}
</div>
</div>
);
},
Expand All @@ -150,7 +158,12 @@ const TableView: React.FC<TableViewProps> = props => {
onRender: item => {
const id = item.dialogId;
return (
<div data-is-focusable={true} key={id} onClick={() => navigateTo(`/bot/${projectId}/dialogs/${id}`)}>
<div
data-is-focusable={true}
key={id}
onClick={() => navigateTo(`/bot/${projectId}/dialogs/${id}`)}
aria-label={formatMessage(`link to where this luis intent defined`)}
>
<Link>{id}</Link>
</div>
);
Expand Down Expand Up @@ -190,7 +203,7 @@ const TableView: React.FC<TableViewProps> = props => {
items: getTemplatesMoreButtons(item, index),
}}
styles={{ menuIcon: { color: NeutralColors.black, fontSize: FontSizes.size16 } }}
ariaLabel={formatMessage('actions')}
ariaLabel={formatMessage('Open inline editor')}
/>
);
},
Expand All @@ -205,7 +218,13 @@ const TableView: React.FC<TableViewProps> = props => {
isCollapsable: true,
data: 'string',
onRender: item => {
return item.state;
return (
<div data-is-focusable={true} css={tableCell}>
<div tabIndex={-1} css={content} aria-label={formatMessage(`State is {state}`, { state: item.state })}>
{item.state}
</div>
</div>
);
},
},
];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ import { TooltipHost } from 'office-ui-fabric-react/lib/Tooltip';
import { ScrollablePane, ScrollbarVisibility } from 'office-ui-fabric-react/lib/ScrollablePane';
import { FontIcon } from 'office-ui-fabric-react/lib/Icon';
import { useMemo, useState } from 'react';
import formatMessage from 'format-message';

import { Pagination } from '../../components/Pagination';

import { INotification } from './types';
import { notification, typeIcon, listRoot, icons, tableView, detailList } from './styles';
import { notification, typeIcon, listRoot, icons, tableView, detailList, tableCell, content } from './styles';

export interface INotificationListProps {
items: INotification[];
Expand Down Expand Up @@ -53,7 +54,17 @@ const columns: IColumn[] = [
isResizable: true,
data: 'string',
onRender: (item: INotification) => {
return <span>{item.severity}</span>;
return (
<div data-is-focusable={true} css={tableCell}>
<div
aria-label={formatMessage(`This is a {severity} notification`, { severity: item.severity })}
tabIndex={-1}
css={content}
>
{item.severity}
</div>
</div>
);
},
isPadded: true,
},
Expand All @@ -67,7 +78,17 @@ const columns: IColumn[] = [
isResizable: true,
data: 'string',
onRender: (item: INotification) => {
return <span>{item.location}</span>;
return (
<div data-is-focusable={true} css={tableCell}>
<div
aria-label={formatMessage(`Location is {location}`, { location: item.location })}
tabIndex={-1}
css={content}
>
{item.location}
</div>
</div>
);
},
isPadded: true,
},
Expand All @@ -83,7 +104,17 @@ const columns: IColumn[] = [
isMultiline: true,
data: 'string',
onRender: (item: INotification) => {
return <span>{item.message}</span>;
return (
<div data-is-focusable={true} css={tableCell}>
<div
aria-label={formatMessage(`Notification Message {msg}`, { msg: item.message })}
tabIndex={-1}
css={content}
>
{item.message}
</div>
</div>
);
},
isPadded: true,
},
Expand Down
11 changes: 11 additions & 0 deletions Composer/packages/client/src/pages/notifications/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,14 @@ export const tableView = css`
export const detailList = css`
overflow-x: hidden;
`;

export const tableCell = css`
outline: none;
:focus {
outline: rgb(102, 102, 102) solid 1px;
}
`;

export const content = css`
outline: none;
`;

0 comments on commit 0ac036f

Please sign in to comment.