@coinbase/eslint-plugin-cds
v3.2.1
Published
ESLint plugin for CDS
Readme
@coinbase/eslint-plugin-cds
Overview
The CDS ESLint Plugin targets gaps in existing accessibility linting and CDS Best Practices that were identified in our CDS A11y linting rules audit.
The CDS Eslint Plugin is integrated into the internal Coinbase eslint plugin and is utilized in two of its configurations:
- 🌐 React: Used in web repositories. Extends
airbnb/rules/react-a11ywhich includes thejsx-a11yplugin. - 📱 React Native: Used in React Native repositories and includes the
react-native-a11yplugin.
In both react and react-native configurations there is a gap in the a11y ruleset that cannot target specific CDS components.
🎯 Our goal with the eslint-plugin-cds package is to create new rules to address these gaps in accessibility and to enforce CDS Best Practices.
Setup
EsLint 9 Flat Config
Eslint v9 introduced the modern Flat Config format for configuration files.
// eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import cds from '@coinbase/eslint-plugin-cds';
export default tseslint.config({
extends: [js.configs.recommended, ...tseslint.configs.recommended, cds.configs.web],
plugins: {
'@coinbase/cds': cds,
},
files: ['**/*.{ts,tsx}'],
});Legacy eslintrc Config
In order to use the CDS plugin in legacy .eslintrc configuration files, you will need to use the legacy configurations.
// .eslintrc.js
module.exports = {
plugins: ['@typescript-eslint', '@coinbase/cds'],
parser: '@typescript-eslint/parser',
extends: ['plugin:@coinbase/cds/web-legacy'],
};Development
Building Locally
To build locally, run
yarn nx run eslint-plugin-cds:buildCreating New Rule
To create a new ESLint rule, you can add your rule from the packages/eslint-plugin-cds/src/rules/ directory.
We have two configs:
- mobile: config containing rules targeting mobile / react-native
- web: config containing rules targeting web / react
After creating a rule, be sure to add it to the appropriate config.
Note: Use AST Explorer with parser set to @typescript-eslint/parser to determine AST node types.
Testing on Consumer Repos Locally
To test on consumer repos locally, you will need to build your eslint-plugin-cds package, add your package to the package.json and modify eslintrc.
Build your local package and pack it.
yarn nx run eslint-plugin-cds:build cd packages/eslint-plugin-cds yarn packAdd your package as a
devDependencyin the consumer'spackage.json. Use the path in your local directory."@coinbase/eslint-plugin-cds": "file:../cds/packages/eslint-plugin-cds/package.tgz",Add the plugin and extend a specific config in the
.eslintrc.js/eslint.confg.jsfile.📝 Note: There are differences between
extendsandplugins:extends: Allows you to use and build upon an existing set of ESLint rules defined in another configuration. Useful for adhering to standardized coding styles like Airbnb or Google.- By using the extends keyword, you're not just making rules available, but you are actively applying a set of predefined rules from another configuration. This means that the rules defined in the extended configurations are automatically enforced in your project, unless explicitly overridden.
plugins: Introduces new rules or environments to ESLint that extend its core capabilities, tailored for specific frameworks or libraries.- When you use plugins, you make a set of additional rules available to your configuration. However, simply including a plugin does not apply those rules. You must explicitly enable the rules provided by the plugin in your configuration file to enforce them in your project. Essentially, plugins expand the rule set that you can choose from, but they don't enforce any rules by default.
Run
yarnin root directory orworkspace.Run
yarn nx run <target>:lintornpx eslint .in root directory orworkspace.- 💡 Tip: Run
npx eslint . > eslint_output.txtto be able to see all the output.
- 💡 Tip: Run
CDS Rules
♿ Accessibility Rules
We currently have two additional accessibility rules:
🔍 controlHasAssociatedLabelExtended (Web)
Rule Description:
The controlHasAssociatedLabelExtended rule checks for the presence of an accessibilityLabel or other specific a11yLabel props on designated Web CDS components.
The accessibilityLabel is required for components listed under componentsRequiringAccessibilityLabel. The rule enforces that these components must have an accessibilityLabel attribute unless:
- They contain inner text, or
- They have props spread which might implicitly handle accessibility.
Targeted Components This rule specifically targets components such as:
ButtonCheckboxInputChipIconButtonIconCounterButtonPressableSwitchTextInputFeedCardProgressBarSelectNavigationBarSidebarPopover
Extended A11y Lint Coverage:
This rule also checks for other required a11y labels that need to be enforced outside of accessibilityLabel.
For components listed under collapsibleCheckForControlledElementAccessibilityProps, this rule ensures that controlledElementAccessibilityProps are provided to manage their accessibility state dynamically.
Extended Targeted Components
Collapsible,Dropdown- Checks for presence of
controlledElementAccessibilityProps
- Checks for presence of
TextInput,SelectStack- Checks for presence of
helperTextErrorIconAccessibilityLabel
- Checks for presence of
DatePicker- Checks for presence of
calendarIconButtonAccessibilityLabel
- Checks for presence of
DatePicker,Calendar,TabNavigation- Checks for presence of
nextArrowAccessibilityLabelandpreviousArrowAccessibilityLabel
- Checks for presence of
NudgeCard,UpsellCard- Checks for presence of
accessibilityLabelwhenonDismissPressis present
- Checks for presence of
SearchInput- Checks for presence of
startIconAccessibilityLabelandclearIconAccessibilityLabel
- Checks for presence of
🔍 hasValidA11yDescriptorsExtended (mobile)
Rule Description:
The hasValidA11yDescriptorsExtended rule verifies that mobile CDS components such as buttons and switches have an accessibilityLabel or other specific a11yLabel props on designated Mobile CDS components. It does not flag components if:
- They contain inner text that serves as an implicit label.
- They have properties spread that can implicitly provide accessibility attributes.
Targeted Components This rule specifically targets components such as:
ButtonCheckboxInputChipIconButtonIconCounterButtonPressableSwitchTextInputFeedCardStickyFooterProgressBarSelectNavigationBarSidebarPopover
Extended A11y Lint Coverage:
This rule also checks for other required a11y labels that need to be enforced outside of accessibilityLabel.
Extended Targeted Components
Drawer,SelectChip,Tray- Checks for presence of
handleBarAccessibilityLabel
- Checks for presence of
TextInput- Checks for presence of
helperTextErrorIconAccessibilityLabel
- Checks for presence of
DatePicker- Checks for presence of
calendarIconButtonAccessibilityLabel
- Checks for presence of
NudgeCard,UpsellCard- Checks for presence of
accessibilityLabelwhenonDismissPressis present
- Checks for presence of
SearchInput- Checks for presence of
startIconAccessibilityLabelandclearIconAccessibilityLabel
- Checks for presence of
Current CDS Best Practices Rules
TBD
Development
Building Locally
To build locally, run
yarn nx run eslint-plugin-cds:buildCreating New Rule
To create a new ESLint rule, you can add your rule from the packages/eslint-plugin-cds/src/rules/ directory.
We have two configs:
- mobile: config containing rules targeting mobile / react-native
- web: config containing rules targeting web / react
After creating a rule, be sure to add it to the appropriate config.
Note: Use AST Explorer with parser set to @typescript-eslint/parser to determine AST node types.
Testing on Consumer Repos Locally
To test on consumer repos locally, you will need to build your eslint-plugin-cds package, add your package to the package.json and modify eslintrc.
Build your local package and pack it.
yarn nx run eslint-plugin-cds:build cd packages/eslint-plugin-cds yarn packAdd your package as a
devDependencyin the consumer'spackage.json. Use the path in your local directory."@coinbase/eslint-plugin-cds": "file:../cds/packages/eslint-plugin-cds/package.tgz",Add the plugin and extend a specific config in the
.eslintrc.js/eslint.confg.jsfile.📝 Note: There are differences between
extendsandplugins:extends: Allows you to use and build upon an existing set of ESLint rules defined in another configuration. Useful for adhering to standardized coding styles like Airbnb or Google.- By using the extends keyword, you're not just making rules available, but you are actively applying a set of predefined rules from another configuration. This means that the rules defined in the extended configurations are automatically enforced in your project, unless explicitly overridden.
plugins: Introduces new rules or environments to ESLint that extend its core capabilities, tailored for specific frameworks or libraries.- When you use plugins, you make a set of additional rules available to your configuration. However, simply including a plugin does not apply those rules. You must explicitly enable the rules provided by the plugin in your configuration file to enforce them in your project. Essentially, plugins expand the rule set that you can choose from, but they don't enforce any rules by default.
Run
yarnin root directory orworkspace.Run
yarn nx run <target>:lintornpx eslint .in root directory orworkspace.- 💡 Tip: Run
npx eslint . > eslint_output.txtto be able to see all the output.
- 💡 Tip: Run
