A CLAUDE.md is just a markdown file at the root of your repo. Copy the content below into your own project's CLAUDE.md to give your agent the same context.
npx versuz@latest install dequelabs-axe-core --kind=claude-mdcurl -o CLAUDE.md https://raw.githubusercontent.com/dequelabs/axe-core/HEAD/CLAUDE.md# axe-core — Claude Code Context
**Last updated:** 2026-03-19
## 0. Fundamental Standards
- **Formatting:** Run `npm run fmt` (Prettier) and `npm run eslint` before every commit. No exceptions.
- **Zero-Exception Testing:** 100% coverage goal. Run `npm test` before completion. `feat`/`fix` and other behavior-changing PRs require unit + integration tests where applicable; see `doc/code-submission-guidelines.md` for exceptions (e.g., some `chore`/docs changes).
- **Import Rule:** Directory-level import restrictions are strictly enforced. See `eslint.config.js`.
- **Commits:** Angular commit convention is mandatory. PRs with non-conforming commits will be rejected. See `doc/code-submission-guidelines.md`.
- **Issues:** All unresolved issues tracked in [GitHub Issues](https://github.com/dequelabs/axe-core/issues).
## 1. Technical Guidelines
### Code Structure
- **Return Early:** Keep the happy path left-aligned. Handle errors/edge cases first with early returns — never nest when you can exit.
- **Exports:** Default export at the top of the file, immediately after imports.
- **JSDoc:** Add JSDoc/DocBlock comments where appropriate, especially for exported APIs and complex logic. Document parameters and return types. See `doc/code-submission-guidelines.md` (source of truth) and `doc/developer-guide.md` for additional guidance.
- **Naming:** Files and rule/check IDs in kebab-case. Functions in camelCase. Booleans prefixed `is`/`has`/`should`. Constants in `UPPER_SNAKE_CASE`.
- **Variables:** Declare at point of use, not at the top of the function.
### Virtual Nodes vs. HTMLElement
- **Prefer Virtual Nodes** for attribute access and property reads (`virtualNode.attr()`, `virtualNode.props`).
- **Use real DOM** only when you need DOM APIs (e.g., `getBoundingClientRect`, `getRootNode`).
- **`core/utils/` functions** should default to real DOM inputs/outputs, except utilities that are explicitly documented as operating on `VirtualNode` (for example, tree or selector helpers). Avoid introducing new `VirtualNode`-dependent utilities unless there is a clear performance or API benefit.
- **Conversion:** Use `getNodeFromTree()` from `core/utils` when you receive an ambiguous input (such as a `VirtualNode`, selector, or mixed type) and need to resolve it to a real DOM `Node`.
### Import Restrictions (Hard Rules)
- `standards/` → nothing (pure data, no imports).
- `core/utils/` → other `core/utils`, `core/base`, `standards` via **direct file paths only** (no index).
- `core/imports/` → node modules **only** (the only place npm imports are allowed).
- `commons/` → other `commons` (direct paths), `core/utils` (index OK).
- `checks/` and `rules/` → any directory (index OK).
- **Never** import `commons` from `core/utils`. This is the most commonly rejected violation.
### Checks & Rules
- **Check evaluate functions:** Return `true` (pass), `false` (fail), or `undefined` (incomplete). Use `this.data()` to pass values to message templates and to provide incomplete-result detail.
- **Rule JSON:** Use `all`, `any`, `none` check arrays. `selector` + optional `matches` to scope candidates. Valid `impact` values: `"minor"`, `"moderate"`, `"serious"`, `"critical"`.
- **Standards data:** Never hardcode ARIA/HTML lists in checks. Query from `standards/` via `commons/standards` functions.
- **Messages:** All user-facing strings live in check/rule JSON `metadata.messages`. Use `${data.property}` templates. Support singular/plural variants. Update `locales/_template.json` whenever messages change (auto-synced on `npm run build`).
### High-Risk Areas (Extra Scrutiny Required)
- **Color contrast:** Handles all CSS color formats, opacity, blend modes, stacking contexts, text-shadow. Return `undefined` when background cannot be determined. See `doc/developer-guide.md`.
- **ARIA validation:** Must stay current with spec. Query roles/attrs from `standards/aria-roles.js` and `standards/aria-attrs.js`. Handle implicit vs. explicit roles. See `doc/rule-development.md`.
- **Hidden elements:** Use `isVisibleToScreenReaders()`, not CSS visibility alone. Account for `aria-hidden="true"` and Shadow DOM boundaries.
- **i18n:** Update `locales/_template.json` on every message change and commit the generated file alongside source.
## 2. Testing
- **Structure:** Mirror `lib/` exactly under `test/`. File `lib/commons/text/sanitize.js` → `test/commons/text/sanitize.js`.
- **Checks:** Use `axe.testUtils.MockCheckContext()`. Only reset `checkContext` in `afterEach` — `fixture` and `axe._tree` are auto-cleared.
- **Integration tests:** All rule changes require an HTML + JSON pair. Use `test/integration/rules/<rule-name>/` for mocha-hosted tests or `test/integration/full/<rule-name>/` when the rule requires a full HTML page. JSON selectors must use axe array format (`["#id"]`; iframes: `["iframe", "#id"]`). Also update or create virtual-rules tests where appropriate.
- **Shadow DOM:** Every relevant check/rule must include an open Shadow DOM test case using `queryShadowFixture`.
- **Logging:** Do not commit `console.log` statements.
## 3. Build & Commits
- **Bundles (`axe.js`, `axe.min.js`)** are auto-generated for releases/publishing and are not committed to the repo (they are gitignored).
- **Locales template (`locales/_template.json`)** is auto-generated. When message strings change, regenerate this file and commit it in the same commit as the source changes — never in a separate commit.
- **One change per PR.** Do not mix refactoring with feature work.
- **Commit format:** `<type>(<scope>): <subject>` — imperative, lowercase, no period, ≤100 chars total. Body explains motivation. Footer: `Closes issue #123` or full URL. See `doc/code-submission-guidelines.md` for the full type list.
**Example:**
```
fix(aria-valid-attr-value): handle multiple aria-errormessage IDs
When aria-errormessage contains multiple space-separated IDs, verify
all IDs exist in aria-describedby instead of matching the full string.
Closes issue #4957
```
## 4. Documentation & API Changes
- **New rules:** Update `CHANGELOG.md`. `doc/rule-descriptions.md` is auto-generated by `npm run build`.
- **API changes:** Update `doc/API.md` and `axe.d.ts` TypeScript definitions.
- **Breaking changes:** Avoid breaking changes — prefer supporting both old and new formats simultaneously. If unavoidable, add `BREAKING CHANGE: description` to commit footer, include migration guide in `CHANGELOG.md`, and tag deprecated code with `@deprecated` JSDoc.
## 5. Examples (Copy-Paste Reference)
- **Code patterns:** `doc/examples/code-patterns.md` — return early, default export, imports, JSDoc, Virtual Node usage
- **Test patterns:** `doc/examples/test-patterns.md` — unit tests, check tests, Shadow DOM tests, integration test HTML+JSON
- **Rule & check templates:** `doc/examples/rule-check-templates.md` — JSON templates for rules and checks, evaluate function pattern
- **PR review patterns:** `doc/examples/pr-review-patterns.md` — common reviewer feedback, anti-patterns, what reviewers look for
## 6. Reference Docs & Help
- **Contributing guide:** `CONTRIBUTING.md`
- **Import rules detail:** `eslint.config.js`
- **Code submission standards:** `doc/code-submission-guidelines.md`
- **Developer guide:** `doc/developer-guide.md`
- **Rule development:** `doc/rule-development.md`
- **API reference:** `doc/API.md`
- **Pull Request Checklist:** `doc/pull-request-checklist.md`
- **Slack:** [axe-community](https://accessibility.deque.com/axe-community)
- **Issues:** [GitHub Issues](https://github.com/dequelabs/axe-core/issues)