Skip to content
Merged
10 changes: 5 additions & 5 deletions COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@ We currently cover the following components:
- [x] Button
- [x] Button
- [X] CompoundButton
- [] MenuButton
- [x] MenuButton
- [X] MenuItem
- [] SplitButton
- [x] SplitButton
- [x] ToggleButton
- [] ToolbarToggleButton
- [] Card
- [] Card
- [x] Card
- [x] Card
- [] CardFooter
- [] CardHeader
- [] CardPreview
Expand All @@ -37,7 +37,7 @@ We currently cover the following components:
- [x] Field
- [N/A] FluentProvider
- [] Image
- [] InfoLabel
- [x] InfoLabel
- [x] Input
- [x] Label
- [x] Link
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ Any use of third-party trademarks or logos are subject to those third-party's po
| [avoid-using-aria-describedby-for-primary-labelling](docs/rules/avoid-using-aria-describedby-for-primary-labelling.md) | aria-describedby provides additional context and is not meant for primary labeling. | βœ… | | |
| [badge-needs-accessible-name](docs/rules/badge-needs-accessible-name.md) | | βœ… | | πŸ”§ |
| [breadcrumb-needs-labelling](docs/rules/breadcrumb-needs-labelling.md) | All interactive elements must have an accessible name | βœ… | | |
| [card-needs-accessible-name](docs/rules/card-needs-accessible-name.md) | Accessibility: Interactive Card must have an accessible name via aria-label, aria-labelledby, etc. | βœ… | | |
| [checkbox-needs-labelling](docs/rules/checkbox-needs-labelling.md) | Accessibility: Checkbox without label must have an accessible and visual label: aria-labelledby | βœ… | | |
| [colorswatch-needs-labelling](docs/rules/colorswatch-needs-labelling.md) | Accessibility: ColorSwatch must have an accessible name via aria-label, Tooltip, aria-labelledby, etc.. | βœ… | | |
| [combobox-needs-labelling](docs/rules/combobox-needs-labelling.md) | All interactive elements must have an accessible name | βœ… | | |
Expand All @@ -128,8 +129,10 @@ Any use of third-party trademarks or logos are subject to those third-party's po
| [image-button-missing-aria](docs/rules/image-button-missing-aria.md) | Accessibility: Image buttons must have accessible labelling: title, aria-label, aria-labelledby, aria-describedby | βœ… | | |
| [image-needs-alt](docs/rules/image-needs-alt.md) | Accessibility: Image must have alt attribute with a meaningful description of the image. If the image is decorative, use alt="". | βœ… | | |
| [imageswatch-needs-labelling](docs/rules/imageswatch-needs-labelling.md) | Accessibility: ImageSwatch must have an accessible name via aria-label, Tooltip, aria-labelledby, etc.. | βœ… | | |
| [infolabel-needs-labelling](docs/rules/infolabel-needs-labelling.md) | Accessibility: InfoLabel must have an accessible name via aria-label, text content, aria-labelledby, etc. | βœ… | | |
| [input-components-require-accessible-name](docs/rules/input-components-require-accessible-name.md) | Accessibility: Input fields must have accessible labelling: aria-label, aria-labelledby or an associated label | βœ… | | |
| [link-missing-labelling](docs/rules/link-missing-labelling.md) | Accessibility: Image links must have an accessible name. Add either text content, labelling to the image or labelling to the link itself. | βœ… | | πŸ”§ |
| [menu-button-needs-labelling](docs/rules/menu-button-needs-labelling.md) | Accessibility: MenuButton must have an accessible name via aria-label, text content, aria-labelledby, etc. | βœ… | | |
| [menu-item-needs-labelling](docs/rules/menu-item-needs-labelling.md) | Accessibility: MenuItem without label must have an accessible and visual label: aria-labelledby | βœ… | | |
| [no-empty-buttons](docs/rules/no-empty-buttons.md) | Accessibility: Button, ToggleButton, SplitButton, MenuButton, CompoundButton must either text content or icon or child component | βœ… | | |
| [no-empty-components](docs/rules/no-empty-components.md) | FluentUI components should not be empty | βœ… | | |
Expand All @@ -142,6 +145,7 @@ Any use of third-party trademarks or logos are subject to those third-party's po
| [spin-button-needs-labelling](docs/rules/spin-button-needs-labelling.md) | Accessibility: SpinButtons must have an accessible label | βœ… | | |
| [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 | βœ… | | |
| [split-button-needs-labelling](docs/rules/split-button-needs-labelling.md) | Accessibility: SplitButton must have an accessible name via aria-label, text content, aria-labelledby, etc. | βœ… | | |
| [swatchpicker-needs-labelling](docs/rules/swatchpicker-needs-labelling.md) | Accessibility: SwatchPicker must have an accessible name via aria-label, aria-labelledby, Field component, etc.. | βœ… | | |
| [switch-needs-labelling](docs/rules/switch-needs-labelling.md) | Accessibility: Switch must have an accessible label | βœ… | | |
| [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. | βœ… | | |
Expand Down
45 changes: 45 additions & 0 deletions docs/rules/card-needs-accessible-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Accessibility: Interactive Card must have an accessible name via aria-label, aria-labelledby, etc (`@microsoft/fluentui-jsx-a11y/card-needs-accessible-name`)

πŸ’Ό This rule is enabled in the βœ… `recommended` config.

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

Interactive Card components must have an accessible name for screen readers.

## Rule Details

This rule enforces that Card components have proper accessible names when they are interactive (clickable).

### Noncompliant

```jsx
<Card>
<CardHeader>
<Text weight="semibold">Card title</Text>
</CardHeader>
</Card>
```

### Compliant

```jsx
<Card aria-label="Product details">
<CardHeader>
<Text weight="semibold">Card title</Text>
</CardHeader>
</Card>

<Card aria-labelledby="card-title">
<CardHeader>
<Text id="card-title" weight="semibold">Card title</Text>
</CardHeader>
</Card>
```

## When Not To Use

If the Card is purely decorative and not interactive, this rule is not necessary.

## Accessibility guidelines

- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
37 changes: 37 additions & 0 deletions docs/rules/infolabel-needs-labelling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Accessibility: InfoLabel must have an accessible name via aria-label, text content, aria-labelledby, etc (`@microsoft/fluentui-jsx-a11y/infolabel-needs-labelling`)

πŸ’Ό This rule is enabled in the βœ… `recommended` config.

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

InfoLabel components must have accessible labelling for screen readers.

## Rule Details

This rule enforces that InfoLabel components have proper accessible names through aria-label, aria-labelledby, or text content.

### Noncompliant

```jsx
<InfoLabel />
```

### Compliant

```jsx
<InfoLabel aria-label="Additional information" />

<InfoLabel aria-labelledby="info-text">
<span id="info-text">Help text</span>
</InfoLabel>

<InfoLabel>Help information</InfoLabel>
```

## When Not To Use

If the InfoLabel is purely decorative, this rule may not be necessary.

## Accessibility guidelines

- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
37 changes: 37 additions & 0 deletions docs/rules/menu-button-needs-labelling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Accessibility: MenuButton must have an accessible name via aria-label, text content, aria-labelledby, etc (`@microsoft/fluentui-jsx-a11y/menu-button-needs-labelling`)

πŸ’Ό This rule is enabled in the βœ… `recommended` config.

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

MenuButton components must have accessible labelling for screen readers.

## Rule Details

This rule enforces that MenuButton components have proper accessible names through aria-label, aria-labelledby, or text content.

### Noncompliant

```jsx
<MenuButton />
```

### Compliant

```jsx
<MenuButton aria-label="Menu options" />

<MenuButton aria-labelledby="menu-label">
<span id="menu-label">Options</span>
</MenuButton>

<MenuButton>Options</MenuButton>
```

## When Not To Use

This rule should always be used for MenuButton components as they are interactive elements.

## Accessibility guidelines

- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
37 changes: 37 additions & 0 deletions docs/rules/split-button-needs-labelling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Accessibility: SplitButton must have an accessible name via aria-label, text content, aria-labelledby, etc (`@microsoft/fluentui-jsx-a11y/split-button-needs-labelling`)

πŸ’Ό This rule is enabled in the βœ… `recommended` config.

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

SplitButton components must have accessible labelling for screen readers.

## Rule Details

This rule enforces that SplitButton components have proper accessible names through aria-label, aria-labelledby, or text content.

### Noncompliant

```jsx
<SplitButton />
```

### Compliant

```jsx
<SplitButton aria-label="Save options" />

<SplitButton aria-labelledby="save-label">
<span id="save-label">Save</span>
</SplitButton>

<SplitButton>Save</SplitButton>
```

## When Not To Use

This rule should always be used for SplitButton components as they are interactive elements.

## Accessibility guidelines

- [WCAG 4.1.2](https://www.w3.org/WAI/WCAG21/Understanding/name-role-value.html)
2 changes: 1 addition & 1 deletion lib/applicableComponents/buttonBasedComponents.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

const applicableComponents = ["Button", "ToggleButton", "CompoundButton"];
const applicableComponents = ["Button", "ToggleButton", "CompoundButton", "MenuButton", "SplitButton"];

module.exports = {
applicableComponents
Expand Down
8 changes: 8 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = {
"@microsoft/fluentui-jsx-a11y/avoid-using-aria-describedby-for-primary-labelling": "error",
"@microsoft/fluentui-jsx-a11y/badge-needs-accessible-name": "error",
"@microsoft/fluentui-jsx-a11y/breadcrumb-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/card-needs-accessible-name": "error",
"@microsoft/fluentui-jsx-a11y/checkbox-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/colorswatch-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/combobox-needs-labelling": "error",
Expand All @@ -35,8 +36,10 @@ module.exports = {
"@microsoft/fluentui-jsx-a11y/image-button-missing-aria": "error",
"@microsoft/fluentui-jsx-a11y/image-needs-alt": "error",
"@microsoft/fluentui-jsx-a11y/imageswatch-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/infolabel-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/input-components-require-accessible-name": "error",
"@microsoft/fluentui-jsx-a11y/link-missing-labelling": "error",
"@microsoft/fluentui-jsx-a11y/menu-button-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/menu-item-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/no-empty-buttons": "error",
"@microsoft/fluentui-jsx-a11y/no-empty-components": "error",
Expand All @@ -49,6 +52,7 @@ module.exports = {
"@microsoft/fluentui-jsx-a11y/spin-button-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/spin-button-unrecommended-labelling": "error",
"@microsoft/fluentui-jsx-a11y/spinner-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/split-button-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/swatchpicker-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/switch-needs-labelling": "error",
"@microsoft/fluentui-jsx-a11y/tablist-and-tabs-need-labelling": "error",
Expand All @@ -65,6 +69,7 @@ module.exports = {
"avoid-using-aria-describedby-for-primary-labelling": rules.avoidUsingAriaDescribedByForPrimaryLabelling,
"badge-needs-accessible-name": rules.badgeNeedsAccessibleName,
"breadcrumb-needs-labelling": rules.breadcrumbNeedsLabelling,
"card-needs-accessible-name": rules.cardNeedsAccessibleName,
"checkbox-needs-labelling": rules.checkboxNeedsLabelling,
"colorswatch-needs-labelling": rules.colorSwatchNeedsLabelling,
"combobox-needs-labelling": rules.comboboxNeedsLabelling,
Expand All @@ -78,8 +83,10 @@ module.exports = {
"image-button-missing-aria": rules.imageButtonMissingAria,
"image-needs-alt": rules.imageNeedsAlt,
"imageswatch-needs-labelling": rules.imageSwatchNeedsLabelling,
"infolabel-needs-labelling": rules.infoLabelNeedsLabelling,
"input-components-require-accessible-name": rules.inputComponentsRequireAccessibleName,
"link-missing-labelling": rules.linkMissingLabelling,
"menu-button-needs-labelling": rules.menuButtonNeedsLabelling,
"menu-item-needs-labelling": rules.menuItemNeedsLabelling,
"no-empty-buttons": rules.noEmptyButtons,
"no-empty-components": rules.noEmptyComponents,
Expand All @@ -92,6 +99,7 @@ module.exports = {
"spin-button-needs-labelling": rules.spinButtonNeedsLabelling,
"spin-button-unrecommended-labelling": rules.spinButtonUnrecommendedLabelling,
"spinner-needs-labelling": rules.spinnerNeedsLabelling,
"split-button-needs-labelling": rules.splitButtonNeedsLabelling,
"swatchpicker-needs-labelling": rules.swatchpickerNeedsLabelling,
"switch-needs-labelling": rules.switchNeedsLabelling,
"tablist-and-tabs-need-labelling": rules.tablistAndTabsNeedLabelling,
Expand Down
26 changes: 26 additions & 0 deletions lib/rules/buttons/menu-button-needs-labelling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { ESLintUtils } from "@typescript-eslint/utils";
import { makeLabeledControlRule } from "../../util/ruleFactory";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

export default ESLintUtils.RuleCreator.withoutDocs(
makeLabeledControlRule({
component: "MenuButton",
messageId: "menuButtonNeedsLabelling",
description: "Accessibility: MenuButton must have an accessible name via aria-label, text content, aria-labelledby, etc.",
labelProps: ["aria-label"],
allowFieldParent: false,
allowHtmlFor: false,
allowLabelledBy: true,
allowWrappingLabel: true,
allowTooltipParent: true,
allowDescribedBy: false,
allowLabeledChild: true,
allowTextContentChild: true
})
);
26 changes: 26 additions & 0 deletions lib/rules/buttons/split-button-needs-labelling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { ESLintUtils } from "@typescript-eslint/utils";
import { makeLabeledControlRule } from "../../util/ruleFactory";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

export default ESLintUtils.RuleCreator.withoutDocs(
makeLabeledControlRule({
component: "SplitButton",
messageId: "splitButtonNeedsLabelling",
description: "Accessibility: SplitButton must have an accessible name via aria-label, text content, aria-labelledby, etc.",
labelProps: ["aria-label"],
allowFieldParent: false,
allowHtmlFor: false,
allowLabelledBy: true,
allowWrappingLabel: true,
allowTooltipParent: true,
allowDescribedBy: false,
allowLabeledChild: true,
allowTextContentChild: true
})
);
26 changes: 26 additions & 0 deletions lib/rules/card-needs-accessible-name.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { ESLintUtils } from "@typescript-eslint/utils";
import { makeLabeledControlRule } from "../util/ruleFactory";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

export default ESLintUtils.RuleCreator.withoutDocs(
makeLabeledControlRule({
component: "Card",
messageId: "cardNeedsAccessibleName",
description: "Accessibility: Interactive Card must have an accessible name via aria-label, aria-labelledby, etc.",
labelProps: ["aria-label"],
allowFieldParent: false,
allowHtmlFor: false,
allowLabelledBy: true,
allowWrappingLabel: false,
allowTooltipParent: true,
allowDescribedBy: false,
allowLabeledChild: true,
allowTextContentChild: true
})
);
Loading
Loading