ESLint Plugin
@airframeui/eslint-plugin works in JSX and Angular 20+ templates. Same seven rules, same version as @airframeui/core: leftover Tailwind/Bootstrap, unknown af-* names, structure classes, redundant defaults, and field-error ARIA.
- JSX — string literals on
class/classNamein.js/.jsx/.ts/.tsx - Angular —
class="…",[class]="'…'",[class.token], and[ngClass]in*.html, including@if/@for/@switch/@defer. Inlinetemplatestrings on@Componentwork whenangular-eslintextracts them.
Install angular-eslint for templates. The plugin does not parse .html as JavaScript. Vue bindings, class:list, and [class]="someVar" are out of scope — use MCP validate_markup for those hosts.
Installation
Section titled “Installation”npm install -D @airframeui/eslint-plugin// eslint.config.js
import airframe from '@airframeui/eslint-plugin';
export default [
airframe.configs['flat/recommended'],
];// eslint.config.js
import airframe from '@airframeui/eslint-plugin';
import angular from 'angular-eslint';
export default [
{
files: ['**/*.ts'],
processor: angular.processInlineTemplates,
},
...angular.configs.templateRecommended,
...airframe.configs['flat/angular'],
];JSX. flat/recommended turns on the rules and JSX parsing for .js / .jsx / .ts / .tsx. Drop it into an existing export default [ … ] array.
Angular (v20+). Use flat/angular with angular-eslint. That preset matches *.html and does not set a parser — templateRecommended (or languageOptions.parser from @angular-eslint/template-parser) must already apply. processInlineTemplates on *.ts covers inline template: strings. Full CSS and template setup: Angular.
An app that has both JSX and Angular can spread flat/recommended and flat/angular in the same config.
Legacy eslintrc
Section titled “Legacy eslintrc”JSX only. Angular templates need flat config (angular-eslint no longer supports eslintrc).
// .eslintrc.cjs
module.exports = {
plugins: ['@airframeui'],
extends: ['plugin:@airframeui/recommended'],
};Autofix
Section titled “Autofix”Rules with a fix rewrite the class string. In Angular that includes static class="…" and [class]="'…'" / [ngClass]="'…'" string literals. [class.token] and [ngClass] object maps are reported without a rewrite. Run npx eslint . --fix or the editor Fix all auto-fixable problems action.
Autofix is only attached when the replacement is deterministic: known aliases, catalog heuristics, structure classes, redundant defaults, and redundant width. Unknown names with only a fuzzy guess, and field-error ARIA, are reported without a fix.
All seven ship in flat/recommended (JSX) and flat/angular (templates).
| Rule | Recommended | Autofix | What it does |
|---|---|---|---|
@airframeui/ | warn | no | Leftover Bootstrap tokens in JSX class / className and Angular class / [class] / [ngClass] |
@airframeui/ | warn | yes | Restated defaults: af-card af-stack, af-btn af-is-primary, af-container af-container-xl, matching af-text-h* |
@airframeui/ | warn | yes | af-w-full on form controls; af-block on af-btn |
@airframeui/ | warn | no | Leftover Tailwind utilities in JSX class / className and Angular class / [class] / [ngClass] |
@airframeui/ | error | yes* | Invented af-* names. Autofix for aliases (af-btn-danger → af-is-danger) |
@airframeui/ | warn | yes | Rewrites flex flex-col, grid grid-cols-*, row, etc. to structure classes |
@airframeui/ | error | no | af-field__error needs id; error inputs need aria-describedby |
Structure class examples
Section titled “Structure class examples”Before and after for @airframeui/prefer-airframe-layout-recipes
| Before | After |
|---|---|
flex flex-col gap-4 | af-stack af-gap-lg |
flex flex-wrap gap-2 | af-inline af-gap-sm |
grid grid-cols-3 gap-6 | af-grid af-grid-3 af-gap-xl |
d-flex flex-column | af-stack |
container | af-container |
Gap numbers map to the Airframe named scale (0 · xs · sm · md · lg · xl · 2xl · 3xl · 4xl). Same mapping as the Tailwind and Bootstrap cheat sheets.
Current limitations
Section titled “Current limitations”- Not Vue/Svelte bindings,
class:list, template literals, Astro expression attributes, or Angular[class]="variable"(non-literal). For other HTML hosts, use MCPvalidate_markup. @airframeui/no-unknown-airframe-classprefers the project’s@airframeui/core/classes.json, then the snapshot generated from core at plugin build time (sameclasses.json+ token catalog as IntelliSense for Airframe). The plugin shares a version withcore/tokens.- Tailwind/Bootstrap detectors ignore existing
af-*tokens so legitimate Airframe markup is not flagged.
- Package README: npm
- Related: Angular, IntelliSense for Airframe, Coming from Bootstrap or Tailwind, Tailwind migration, Bootstrap migration