Skip to content

Commit

Permalink
implement accessible grid, make scroll container elements overridable
Browse files Browse the repository at this point in the history
  • Loading branch information
priley86 committed May 17, 2019
1 parent a61d00f commit fa83e87
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ const propTypes = {
throw new Error('Specify at least one of: header, caption, aria-label');
}
return null;
}
},
role: PropTypes.string
};

const defaultProps = {
Expand All @@ -158,7 +159,8 @@ const defaultProps = {
contentId: 'expanded-content',
dropdownPosition: DropdownPosition.right,
dropdownDirection: DropdownDirection.down,
gridBreakPoint: TableGridBreakpoint.gridMd
gridBreakPoint: TableGridBreakpoint.gridMd,
role: 'grid'
};

export const TableContext = React.createContext();
Expand Down Expand Up @@ -207,6 +209,7 @@ class Table extends React.Component {
bodyWrapper,
rowWrapper,
borders,
role,
...props
} = this.props;

Expand Down Expand Up @@ -249,7 +252,7 @@ class Table extends React.Component {
}
}}
columns={headerData}
role="grid"
role={role}
className={css(
styles.table,
gridBreakPoint && getModifier(stylesGrid, gridBreakPoint),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type ScrollPosition = {
type Props = {
'aria-label': string,
'aria-readonly'?: boolean,
'aria-rowcount': number,

/**
* Set the width of the inner scrollable container to 'auto'.
Expand Down Expand Up @@ -217,7 +218,13 @@ type Props = {
tabIndex: ?number,

/** Width of VirtualGrid; this property determines the number of visible (vs virtualized) columns. */
width: number
width: number,

/** Scroll Container element to render */
scrollContainerComponent: string | React.ComponentType<any>,

/** Inner Scroll Container element to render */
innerScrollContainerComponent: string | React.ComponentType<any>
};

type InstanceProps = {
Expand Down Expand Up @@ -256,6 +263,7 @@ type State = {
*/
class VirtualGrid extends React.PureComponent<Props, State> {
static defaultProps = {
'aria-rowcount': 0,
'aria-label': 'grid',
'aria-readonly': true,
autoContainerWidth: false,
Expand All @@ -281,7 +289,9 @@ class VirtualGrid extends React.PureComponent<Props, State> {
scrollToRow: -1,
style: {},
tabIndex: 0,
isScrollingOptOut: false
isScrollingOptOut: false,
scrollContainerComponent: 'div',
innerScrollContainerComponent: 'div'
};

// Invokes onSectionRendered callback only when start/stop row or column indices change
Expand Down Expand Up @@ -900,7 +910,9 @@ class VirtualGrid extends React.PureComponent<Props, State> {
role,
style,
tabIndex,
width
width,
scrollContainerComponent,
innerScrollContainerComponent
} = this.props;
const { instanceProps, needToResetStyleCache } = this.state;

Expand Down Expand Up @@ -961,44 +973,50 @@ class VirtualGrid extends React.PureComponent<Props, State> {

const showNoContentRenderer = childrenToDisplay.length === 0 && height > 0 && width > 0;

return (
<table
ref={this._setScrollingContainerRef}
{...containerProps}
aria-label={this.props['aria-label']}
aria-readonly={this.props['aria-readonly']}
className={clsx('ReactVirtualized__VirtualGrid', className)}
id={id}
onScroll={this._onScroll}
role={role}
style={{
...gridStyle,
...style
}}
tabIndex={tabIndex}
>
{childrenToDisplay.length > 0 && (
<tbody
className="ReactVirtualized__VirtualGrid__innerScrollContainer"
role={containerRole}
style={{
width: autoContainerWidth ? 'auto' : totalColumnsWidth,
height: totalRowsHeight,
maxWidth: totalColumnsWidth,
maxHeight: totalRowsHeight,
overflow: 'hidden',
pointerEvents: isScrolling ? 'none' : '',
position: 'relative',
display: 'block',
...containerStyle
}}
>
{childrenToDisplay}
</tbody>
)}
{showNoContentRenderer && noContentRenderer()}
</table>
);
const scrollContainerProps = {
...containerProps,
ref: this._setScrollingContainerRef,
'aria-label': this.props['aria-label'],
'aria-rowcount': this.props['aria-rowcount'],
'aria-readonly': this.props['aria-readonly'],
className: clsx('ReactVirtualized__VirtualGrid', className),
id,
onScroll: this._onScroll,
role,
style: {
...gridStyle,
...style
},
tabIndex
};

let innerScrollContainer = null;
if (childrenToDisplay.length > 0) {
const innerScrollContainerProps = {
className: 'ReactVirtualized__VirtualGrid__innerScrollContainer',
role: containerRole,
style: {
width: autoContainerWidth ? 'auto' : totalColumnsWidth,
height: totalRowsHeight,
maxWidth: totalColumnsWidth,
maxHeight: totalRowsHeight,
overflow: 'hidden',
pointerEvents: isScrolling ? 'none' : '',
position: 'relative',
display: 'block',
...containerStyle
}
};
innerScrollContainer = React.createElement(
innerScrollContainerComponent,
innerScrollContainerProps,
childrenToDisplay
);
}
return React.createElement(scrollContainerComponent, scrollContainerProps, [
innerScrollContainer,
showNoContentRenderer && noContentRenderer()
]);
}

/* ---------------------------- Helper methods ---------------------------- */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import clsx from 'clsx';

type Props = {
'aria-label'?: string,
'aria-rowcount?': number,

/**
* Removes fixed height from the scrollingContainer so that the total height
Expand Down Expand Up @@ -194,13 +195,21 @@ export default class VirtualTableBody extends React.PureComponent<Props> {
}

render() {
const { className, noRowsRenderer, scrollToIndex, width, columns, rows } = this.props;
const { className, noRowsRenderer, scrollToIndex, width, columns, rows, tabIndex } = this.props;

const classNames = clsx('ReactVirtualized__List', className);

return (
// note: these aria props if rendered will break a11y for role="presentation"
// this approach attempts to fix non standard table grids
// see: https://www.html5accessibility.com/tests/aria-table-fix.html
<VirtualGrid
{...this.props}
aria-label={null}
aria-readonly={null}
aria-rowcount={null}
tabIndex={null}
role="presentation"
autoContainerWidth
cellRenderer={this._cellRenderer}
className={classNames}
Expand All @@ -213,6 +222,8 @@ export default class VirtualTableBody extends React.PureComponent<Props> {
scrollToRow={scrollToIndex}
columns={columns}
rows={rows}
scrollContainerComponent="table"
innerScrollContainerComponent="tbody"
/>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,24 +87,27 @@ class VirtualizedExample extends React.Component {
key={key}
parent={parent}
rowIndex={index}>
<tr style={style} className={className}>
<td className={columns[0].props.className}>{text}</td>
<td className={columns[1].props.className}>{text}</td>
<td className={columns[2].props.className}>{text}</td>
<td className={columns[3].props.className}>{text}</td>
<td className={columns[4].props.className}>{text}</td>
<tr style={style} className={className} role="row">
<td className={columns[0].props.className} role="gridcell">{text}</td>
<td className={columns[1].props.className} role="gridcell">{text}</td>
<td className={columns[2].props.className} role="gridcell">{text}</td>
<td className={columns[3].props.className} role="gridcell">{text}</td>
<td className={columns[4].props.className} role="gridcell">{text}</td>
</tr>
</CellMeasurer>;
}

return (
<div>
<div
aria-label="Scrollable Table"
role="grid"
aria-rowcount={rows.length}>
<Table
caption="Simple Table"
cells={columns}
rows={rows}
aria-rowcount={rows.length}
gridBreakPoint={TableGridBreakpoint.none}
role="presentation"
>
<TableHeader />
</Table>
Expand Down Expand Up @@ -226,26 +229,29 @@ class SortableExample extends React.Component {
key={key}
parent={parent}
rowIndex={index}>
<tr style={style} className={className}>
<td className={columns[0].props.className}>{text}</td>
<td className={columns[1].props.className}>{text}</td>
<td className={columns[2].props.className}>{text}</td>
<td className={columns[3].props.className}>{text}</td>
<td className={columns[4].props.className}>{text}</td>
<tr style={style} className={className} role="row">
<td className={columns[0].props.className} role="gridcell">{text}</td>
<td className={columns[1].props.className} role="gridcell">{text}</td>
<td className={columns[2].props.className} role="gridcell">{text}</td>
<td className={columns[3].props.className} role="gridcell">{text}</td>
<td className={columns[4].props.className} role="gridcell">{text}</td>
</tr>
</CellMeasurer>;
}

return (
<div>
<div
aria-label="Scrollable Table"
role="grid"
aria-rowcount={rows.length}>
<Table
caption="Sortable Virtualized Table"
cells={columns}
rows={rows}
aria-rowcount={rows.length}
gridBreakPoint={TableGridBreakpoint.none}
sortBy={sortBy}
onSort={this.onSort}
role="presentation"
>
<TableHeader />
</Table>
Expand Down Expand Up @@ -371,30 +377,34 @@ class SelectableExample extends React.Component {
key={key}
parent={parent}
rowIndex={index}>
<tr data-id={index} style={style} className={className}>
<td data-key="0" className="pf-c-table__check">
<tr data-id={index} style={style} className={className} role="row">
<td data-key="0" className="pf-c-table__check" role="gridcell">
<input type="checkbox" checked={rows[index].selected}
onChange={(e) =>
{ this.onSelect(e, e.target.checked, 0, {id: rows[index].id})}}
/>
</td>
<td className={columns[0].props.className}>{text}</td>
<td className={columns[1].props.className}>{text}</td>
<td className={columns[2].props.className}>{text}</td>
<td className={columns[3].props.className}>{text}</td>
<td className={columns[0].props.className} role="gridcell">{text}</td>
<td className={columns[1].props.className} role="gridcell">{text}</td>
<td className={columns[2].props.className} role="gridcell">{text}</td>
<td className={columns[3].props.className} role="gridcell">{text}</td>
</tr>
</CellMeasurer>;
}

return (
<div>
<div
aria-label="Scrollable Table"
role="grid"
aria-rowcount={rows.length}>
<Table
caption="Selectable Virtualized Table"
cells={columns}
rows={rows}
aria-rowcount={rows.length}
gridBreakPoint={TableGridBreakpoint.none}
onSelect={this.onSelect}
role="presentation"
>
<TableHeader />
</Table>
Expand Down Expand Up @@ -519,13 +529,13 @@ class ActionsExample extends React.Component {
key={key}
parent={parent}
rowIndex={index}>
<tr data-id={index} style={style} className={className}>
<td className={columns[0].props.className}>{text}</td>
<td className={columns[1].props.className}>{text}</td>
<td className={columns[2].props.className}>{text}</td>
<td className={columns[3].props.className}>{text}</td>
<td className={columns[4].props.className}>{text}</td>
<td className={columns[5].props.className}>
<tr data-id={index} style={style} className={className} role="row">
<td className={columns[0].props.className} role="gridcell">{text}</td>
<td className={columns[1].props.className} role="gridcell">{text}</td>
<td className={columns[2].props.className} role="gridcell">{text}</td>
<td className={columns[3].props.className} role="gridcell">{text}</td>
<td className={columns[4].props.className} role="gridcell">{text}</td>
<td className={columns[5].props.className} role="gridcell">
<ActionsColumn
items={actions}
rowData={rows[index]}
Expand All @@ -537,13 +547,16 @@ class ActionsExample extends React.Component {
}

return (
<div>
<div
aria-label="Scrollable Table"
role="grid"
aria-rowcount={rows.length}>
<Table
caption="Actions Virtualized Table"
cells={columns}
rows={rows}
aria-rowcount={rows.length}
gridBreakPoint={TableGridBreakpoint.none}
role="presentation"
>
<TableHeader />
</Table>
Expand Down
Loading

0 comments on commit fa83e87

Please sign in to comment.