@coinbase/eslint-plugin-cds
v3.4.0
Published
ESLint plugin for CDS
Readme
Overview
The CDS ESLint Plugin targets CDS best practices to ensure components are being used in accordance with our guidelines and remain accessible.
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.
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 Rules
You can scaffold a new rule using the generator script:
yarn node packages/eslint-plugin-cds/scripts/scaffold-new-rule.mjs <rule-name>This creates the rule source file and a matching test file with boilerplate already in place.
To create a rule manually, follow the steps below.
Step-by-step checklist
- Create the rule file in
src/rules/. Usesrc/templates/custom-rule.tsas a starting point, or copy an existing rule. - Register the rule by adding an import and entry in
src/rules.ts. - Add the rule to a config in
src/configs/. Choose the config that matches the rule's platform:web-- rules targeting web / React codebasesmobile-- rules targeting mobile / React Native codebases
- Write tests in
tests/. Each rule should have a corresponding<rule-name>.test.tsfile using@typescript-eslint/rule-tester. - Document the rule in this README under the appropriate category in the CDS Rules section.
- Update the rules summary table at the top of the CDS Rules section.
Authoring patterns
There are two patterns for defining a rule:
TSESLint.RuleModule-- a plain rule module, good for simple rules (seeno-v7-imports.tsfor an example).ESLintUtils.RuleCreator-- a factory that generates documentation URLs from the rule name. Preferred for rules that benefit from linked documentation (seecontrol-has-associated-label-extended.tsfor an example).
Useful resources
- ESLint custom rule tutorial
- AST Explorer (set parser to
@typescript-eslint/parser) - ESLint Explorer
Available configs
web: rules targeting web / React codebases (includes CDS web rules +jsx-a11y)mobile: rules targeting mobile / React Native codebases (includes CDS mobile rules +react-native-a11y)
Testing on External 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
Rules Overview
| Rule | Category | Platform | Included in Config |
| --------------------------------------------------------------------------------- | ------------- | -------- | ------------------ |
| controlHasAssociatedLabelExtended | Accessibility | Web | web |
| hasValidA11yDescriptorsExtended | Accessibility | Mobile | mobile |
| webChartScrubbingAccessibility | Accessibility | Web | web |
| mobileChartScrubbingAccessibility | Accessibility | Mobile | mobile |
| webTooltipInteractiveContent | Accessibility | Web | web |
| noV7Imports | Migration | Web | web |
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.
🔍 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.
🔍 webChartScrubbingAccessibility (web)
Rule Description:
The webChartScrubbingAccessibility rule enforces chart accessibility descriptors when web chart scrubbing is enabled with the enableScrubbing prop.
Extended Targeted Components
LineChart,BarChart,CartesianChart,AreaChart- Checks for chart-level accessible naming via
accessibilityLabeloraria-labelledby - Checks for scrubber-level labels via either:
getScrubberAccessibilityLabel, or<Scrubber accessibilityLabel={...} />child
- Checks for chart-level accessible naming via
🔍 mobileChartScrubbingAccessibility (mobile)
Rule Description:
The mobileChartScrubbingAccessibility rule enforces chart accessibility descriptors when mobile chart scrubbing is enabled with the prop enableScrubbing.
Extended Targeted Components
LineChart,BarChart,CartesianChart,AreaChart- Checks for chart-level accessible naming via
accessibilityLabeloraria-labelledby - Checks for per-point labels via
getScrubberAccessibilityLabel
- Checks for chart-level accessible naming via
🔍 webTooltipInteractiveContent (web)
Rule Description:
The webTooltipInteractiveContent rule requires hasInteractiveContent when tooltip content includes interactive elements (for example buttons or links), matching CDS tooltip accessibility guidance.
