Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ We currently cover the following components:
- [x] Checkbox
- [] ColorPicker
- [x] Combobox
- [] DataGrid
- [x] DataGrid
- [x] Dialog
- [N/A] Divider
- [] Drawer
Expand Down Expand Up @@ -70,7 +70,7 @@ We currently cover the following components:
- [N/A] SwatchPickerRow
- [x] Switch
- [] SearchBox
- [] Table
- [x] Table
- [x] TabList
- [] Tag
- [] InteractionTag
Expand All @@ -83,7 +83,7 @@ We currently cover the following components:
- [] Toast
- [x] Toolbar
- [x] Tooltip
- [] Tree
- [x] Tree
- [x] Datepicker
- [N/A] Calendar
- [x] Timepicker
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ Any use of third-party trademarks or logos are subject to those third-party's po
| [combobox-needs-labelling](docs/rules/combobox-needs-labelling.md) | All interactive elements must have an accessible name | ✅ | | |
| [compound-button-needs-labelling](docs/rules/compound-button-needs-labelling.md) | Accessibility: Compound buttons must have accessible labelling: title, aria-label, aria-labelledby, aria-describedby | ✅ | | |
| [counter-badge-needs-count](docs/rules/counter-badge-needs-count.md) | | ✅ | | 🔧 |
| [datagrid-needs-labelling](docs/rules/datagrid-needs-labelling.md) | Accessibility: DataGrid must have proper labelling and follow ARIA grid patterns for complex data tables | ✅ | | |
| [dialogbody-needs-title-content-and-actions](docs/rules/dialogbody-needs-title-content-and-actions.md) | A DialogBody should have a header(DialogTitle), content(DialogContent), and footer(DialogActions) | ✅ | | |
| [dialogsurface-needs-aria](docs/rules/dialogsurface-needs-aria.md) | DialogueSurface need accessible labelling: aria-describedby on DialogueSurface and aria-label or aria-labelledby(if DialogueTitle is missing) | ✅ | | |
| [dropdown-needs-labelling](docs/rules/dropdown-needs-labelling.md) | Accessibility: Dropdown menu must have an id and it needs to be linked via htmlFor of a Label | ✅ | | |
Expand All @@ -209,11 +210,13 @@ Any use of third-party trademarks or logos are subject to those third-party's po
| [spin-button-unrecommended-labelling](docs/rules/spin-button-unrecommended-labelling.md) | Accessibility: Unrecommended accessibility labelling - SpinButton | ✅ | | |
| [spinner-needs-labelling](docs/rules/spinner-needs-labelling.md) | Accessibility: Spinner must have either aria-label or label, aria-live and aria-busy attributes | ✅ | | |
| [switch-needs-labelling](docs/rules/switch-needs-labelling.md) | Accessibility: Switch must have an accessible label | ✅ | | |
| [table-needs-labelling](docs/rules/table-needs-labelling.md) | Accessibility: Table must have proper labelling and semantic structure for screen readers | ✅ | | |
| [tablist-and-tabs-need-labelling](docs/rules/tablist-and-tabs-need-labelling.md) | This rule aims to ensure that Tabs with icons but no text labels have an accessible name and that Tablist is properly labeled. | ✅ | | |
| [tag-dismissible-needs-labelling](docs/rules/tag-dismissible-needs-labelling.md) | This rule aims to ensure that dismissible Tag components have proper accessibility labelling: either aria-label on dismissIcon or aria-label on Tag with role on dismissIcon | ✅ | | |
| [tag-needs-name](docs/rules/tag-needs-name.md) | Accessibility: Tag must have an accessible name | ✅ | | |
| [toolbar-missing-aria](docs/rules/toolbar-missing-aria.md) | Accessibility: Toolbars need accessible labelling: aria-label or aria-labelledby | ✅ | | |
| [tooltip-not-recommended](docs/rules/tooltip-not-recommended.md) | Accessibility: Prefer text content or aria over a tooltip for these components MenuItem, SpinButton | ✅ | | |
| [tree-needs-labelling](docs/rules/tree-needs-labelling.md) | Accessibility: Tree must have proper labelling and follow ARIA tree pattern for hierarchical navigation | ✅ | | |
| [visual-label-better-than-aria-suggestion](docs/rules/visual-label-better-than-aria-suggestion.md) | Visual label is better than an aria-label because sighted users can't read the aria-label text. | | ✅ | |

<!-- end auto-generated rules list -->
85 changes: 85 additions & 0 deletions docs/rules/datagrid-needs-labelling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Accessibility: DataGrid must have proper labelling and follow ARIA grid patterns for complex data tables (`@microsoft/fluentui-jsx-a11y/datagrid-needs-labelling`)

💼 This rule is enabled in the ✅ `recommended` config.

<!-- end auto-generated rule header -->

DataGrid components must have accessible labelling for screen readers to understand the data structure and purpose.

## Rule Details

This rule enforces that DataGrid components have proper accessible names and follow ARIA grid patterns for complex data tables. DataGrids present tabular data that requires clear identification for assistive technology users.

DataGrids must have an accessible name provided through one of these methods:
- `aria-label` attribute with descriptive text
- `aria-labelledby` attribute referencing existing label elements
- Wrapping in a `Field` component that provides labeling context

### Noncompliant

```jsx
// Missing any form of accessible labeling
<DataGrid columns={columns} items={employees} />

// Empty or whitespace-only labels
<DataGrid aria-label="" columns={columns} items={data} />
<DataGrid aria-label=" " columns={columns} items={data} />

// Invalid aria-labelledby reference
<DataGrid aria-labelledby="non-existent-id" columns={columns} items={data} />
```

### Compliant

```jsx
// Using aria-label
<DataGrid
aria-label="Employee directory"
columns={columns}
items={employees}
/>

// Using aria-labelledby with existing elements
<Label id="data-grid-title">Sales Report Q3 2024</Label>
<DataGrid
aria-labelledby="data-grid-title"
columns={columns}
items={salesData}
/>

// Wrapped in Field component
<Field label="Product Inventory">
<DataGrid columns={productColumns} items={inventory} />
</Field>

// Best practice: Include row/column counts for large datasets
<DataGrid
aria-label="Financial data with 500 rows and 12 columns"
aria-rowcount={500}
aria-colcount={12}
columns={columns}
items={financialData}
/>
```

## Best Practices

1. **Descriptive Labels**: Use clear, descriptive labels that explain the data's purpose
2. **Data Context**: Include information about the data type (e.g., "Employee directory", "Sales report")
3. **Size Hints**: For large datasets, consider mentioning approximate size in the label
4. **Multiple Labels**: Use `aria-labelledby` to reference multiple elements for richer context

## When Not To Use

This rule should always be used for DataGrid components as they present complex tabular data that requires clear identification for screen reader users.

## Related Rules

- `table-needs-labelling` - Similar requirements for Table components
- `field-needs-labelling` - Field wrapper component labeling

## Accessibility Guidelines

- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
- [ARIA Grid Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/)
- [ARIA Table Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/table/)
103 changes: 103 additions & 0 deletions docs/rules/table-needs-labelling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Accessibility: Table must have proper labelling and semantic structure for screen readers (`@microsoft/fluentui-jsx-a11y/table-needs-labelling`)

💼 This rule is enabled in the ✅ `recommended` config.

<!-- end auto-generated rule header -->

Table components must have accessible labelling for screen readers to understand the table's purpose and content structure.

## Rule Details

This rule enforces that Table components have proper accessible names following semantic HTML and ARIA best practices. Tables present structured data that requires clear identification for assistive technology users.

Tables must have an accessible name provided through one of these methods:
- `aria-label` attribute with descriptive text
- `aria-labelledby` attribute referencing existing label elements
- `<caption>` element providing semantic table description
- Wrapping in a `Field` component that provides labeling context

### Noncompliant

```jsx
// Missing any form of accessible labeling
<Table>
<TableHeader />
<TableBody />
</Table>

// Empty labels don't provide accessibility
<Table aria-label="">
<TableHeader />
<TableBody />
</Table>

// Invalid reference
<Table aria-labelledby="missing-id">
<TableHeader />
<TableBody />
</Table>
```

### Compliant

```jsx
// Using aria-label
<Table aria-label="Product inventory">
<TableHeader>
<TableRow>
<TableHeaderCell>Product</TableHeaderCell>
<TableHeaderCell>Stock</TableHeaderCell>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Widget A</TableCell>
<TableCell>150</TableCell>
</TableRow>
</TableBody>
</Table>

// Using semantic caption element (preferred)
<Table>
<caption>Sales Performance Q3 2024</caption>
<TableHeader />
<TableBody />
</Table>

// Using aria-labelledby
<h2 id="table-title">Employee Directory</h2>
<Table aria-labelledby="table-title">
<TableHeader />
<TableBody />
</Table>

// Wrapped in Field component
<Field label="Financial Summary">
<Table>
<TableHeader />
<TableBody />
</Table>
</Field>
```

## Best Practices

1. **Prefer `<caption>`**: Use caption elements for semantic table labeling when possible
2. **Descriptive Labels**: Clearly describe the table's content and purpose
3. **Context Information**: Include relevant time periods, data scope, or categories
4. **Consistent Structure**: Ensure tables have proper TableHeader and TableBody elements

## When Not To Use

This rule should always be used for Table components as they present structured data that requires clear identification for screen reader users.

## Related Rules

- `datagrid-needs-labelling` - Similar requirements for DataGrid components
- `field-needs-labelling` - Field wrapper component labeling

## Accessibility Guidelines

- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
- [ARIA Table Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/table/)
- [HTML Table Accessibility](https://webaim.org/techniques/tables/)
98 changes: 98 additions & 0 deletions docs/rules/tree-needs-labelling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# Accessibility: Tree must have proper labelling and follow ARIA tree pattern for hierarchical navigation (`@microsoft/fluentui-jsx-a11y/tree-needs-labelling`)

💼 This rule is enabled in the ✅ `recommended` config.

<!-- end auto-generated rule header -->

Tree components must have accessible labelling for screen readers to understand the hierarchical structure and navigation purpose.

## Rule Details

This rule enforces that Tree components have proper accessible names following ARIA tree pattern guidelines. Trees present hierarchical data that requires clear identification for assistive technology users to understand the navigation context.

Trees must have an accessible name provided through one of these methods:
- `aria-label` attribute with descriptive text
- `aria-labelledby` attribute referencing existing label elements
- Wrapping in a `Field` component that provides labeling context

### Noncompliant

```jsx
// Missing any form of accessible labeling
<Tree>
<TreeItem>Folder 1</TreeItem>
<TreeItem>Folder 2</TreeItem>
</Tree>

// Empty or whitespace-only labels
<Tree aria-label="">
<TreeItem>Item 1</TreeItem>
</Tree>

// Invalid aria-labelledby reference
<Tree aria-labelledby="non-existent-id">
<TreeItem>Item 1</TreeItem>
</Tree>
```

### Compliant

```jsx
// Using aria-label
<Tree aria-label="File explorer">
<TreeItem>
<TreeItemLayout>Documents</TreeItemLayout>
<Tree>
<TreeItem>Resume.pdf</TreeItem>
<TreeItem>Cover Letter.docx</TreeItem>
</Tree>
</TreeItem>
<TreeItem>Images</TreeItem>
</Tree>

// Using aria-labelledby
<h3 id="nav-tree">Site Navigation</h3>
<Tree aria-labelledby="nav-tree">
<TreeItem>Home</TreeItem>
<TreeItem>Products</TreeItem>
<TreeItem>Contact</TreeItem>
</Tree>

// Wrapped in Field component
<Field label="Organization Chart">
<Tree>
<TreeItem>CEO</TreeItem>
<TreeItem>VP Engineering</TreeItem>
</Tree>
</Field>

// Complex labeling with instructions
<h3 id="tree-title">Project Files</h3>
<p id="tree-instructions">Use arrow keys to navigate, Enter to open</p>
<Tree aria-labelledby="tree-title tree-instructions">
<TreeItem>src/</TreeItem>
<TreeItem>docs/</TreeItem>
<TreeItem>tests/</TreeItem>
</Tree>
```

## Best Practices

1. **Context Description**: Clearly describe what the tree represents (file system, navigation, org chart)
2. **Navigation Hints**: Consider including keyboard navigation instructions in labels
3. **Scope Information**: Indicate the breadth or type of items in the tree
4. **Hierarchical Context**: Help users understand the tree's organizational purpose

## When Not To Use

This rule should always be used for Tree components as they present complex hierarchical navigation that requires clear identification for screen reader users.

## Related Rules

- `field-needs-labelling` - Field wrapper component labeling

## Accessibility Guidelines

- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
- [ARIA Tree Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/treeview/)
- [ARIA Navigation Landmarks](https://www.w3.org/WAI/ARIA/apg/practices/landmark-regions/)
6 changes: 6 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ module.exports = {
"@microsoft/fluentui-jsx-a11y/combobox-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/compound-button-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/counter-badge-needs-count": "error",
"@microsoft/fluentui-jsx-a11y/datagrid-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/dialogbody-needs-title-content-and-actions": "error",
"@microsoft/fluentui-jsx-a11y/dialogsurface-needs-aria": "error",
"@microsoft/fluentui-jsx-a11y/dropdown-needs-labelling": "error",
Expand All @@ -53,11 +54,13 @@ module.exports = {
"@microsoft/fluentui-jsx-a11y/spin-button-unrecommended-labelling": "error",
"@microsoft/fluentui-jsx-a11y/spinner-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/switch-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/table-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/tablist-and-tabs-need-labelling": "error",
"@microsoft/fluentui-jsx-a11y/tag-dismissible-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/tag-needs-name": "error",
"@microsoft/fluentui-jsx-a11y/toolbar-missing-aria": "error",
"@microsoft/fluentui-jsx-a11y/tooltip-not-recommended": "error",
"@microsoft/fluentui-jsx-a11y/tree-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/visual-label-better-than-aria-suggestion": "warn"
}
}
Expand All @@ -75,6 +78,7 @@ module.exports = {
"combobox-needs-labelling": rules.comboboxNeedsLabelling,
"compound-button-needs-labelling": rules.compoundButtonNeedsLabelling,
"counter-badge-needs-count": rules.counterBadgeNeedsCount,
"datagrid-needs-labelling": rules.dataGridNeedsLabelling,
"dialogbody-needs-title-content-and-actions": rules.dialogbodyNeedsTitleContentAndActions,
"dialogsurface-needs-aria": rules.dialogsurfaceNeedsAria,
"dropdown-needs-labelling": rules.dropdownNeedsLabelling,
Expand All @@ -100,11 +104,13 @@ module.exports = {
"spin-button-unrecommended-labelling": rules.spinButtonUnrecommendedLabelling,
"spinner-needs-labelling": rules.spinnerNeedsLabelling,
"switch-needs-labelling": rules.switchNeedsLabelling,
"table-needs-labelling": rules.tableNeedsLabelling,
"tablist-and-tabs-need-labelling": rules.tablistAndTabsNeedLabelling,
"tag-dismissible-needs-labelling": rules.tagDismissibleNeedsLabelling,
"tag-needs-name": rules.tagNeedsName,
"toolbar-missing-aria": rules.toolbarMissingAria,
"tooltip-not-recommended": rules.tooltipNotRecommended,
"tree-needs-labelling": rules.treeNeedsLabelling,
"visual-label-better-than-aria-suggestion": rules.visualLabelBetterThanAriaSuggestion
}
};
Expand Down
Loading
Loading