@akanaka-design/eslint-config
v0.2.10
Published
ESLint config for Akanaka Design System
Maintainers
Readme
@akanaka-design/eslint-config
ESLint configuration for enforcing Akanaka Design System rules.
Documentation: akanaka-design-system-docs.vercel.app
Repository: github.com/designfresh/akanaka-design-system
Features
- 🎨 Prevents hardcoded colors - enforces design token usage
- 🧩 Validates component imports - ensures components exist in registry
- 🎯 Smart suggestions - suggests nearest valid token based on color similarity
- ⚡ Fast & lightweight - zero runtime dependencies
- 🔧 Works everywhere - Cursor, VS Code, CI/CD pipelines
Installation
pnpm add -D @akanaka-design/eslint-config
# or
npm install --save-dev @akanaka-design/eslint-configUsage
Basic Setup
In your .eslintrc.js or .eslintrc.cjs:
module.exports = {
extends: ['@akanaka-design/eslint-config'],
};With Next.js
module.exports = {
extends: [
'@akanaka-design/eslint-config',
'next/core-web-vitals',
],
};With TypeScript
module.exports = {
extends: [
'@akanaka-design/eslint-config',
'plugin:@typescript-eslint/recommended',
],
parser: '@typescript-eslint/parser',
};Rules
akanaka/prefer-ds-components
Enforces DS-first dashboard composition in two ways:
- Flags custom card-like dashboard
divmarkup and recommendsCardusage - Flags visual
classNameoverrides on DS components imported from@akanaka-design/components
Forbidden visual className patterns on DS components:
- Border styling:
border,border-* - Radius:
rounded,rounded-* - Colors:
bg-*,text-*(excepttext-left,text-center,text-right) - Shadows:
shadow,shadow-* - Typography:
font,font-*
Allowed layout-oriented className patterns:
- Spacing/layout:
m-*,mt-*,mb-*,mx-*,my-*,flex,grid,justify-*,items-* - Sizing/placement:
w-*,h-*,col-span-*
❌ Bad:
import { Card } from '@akanaka-design/components';
<Card className="border-l-4 border-l-primary bg-primary-50">
...
</Card>✅ Good:
import { Card } from '@akanaka-design/components';
<Card className="mt-4 col-span-2 w-full">
...
</Card>akanaka/require-statcard-for-metrics
Dashboard-only (same path rules as prefer-ds-components): flags hand-built KPI tiles—div or span with background + rounded corners + padding that contain a small label line and a large numeric value line—and requires StatCard from @akanaka-design/components (documented on the components site) instead.
❌ Bad:
<div className="bg-[var(--primary)]/10 rounded-lg p-4">
<p className="text-sm">Total Staff</p>
<p className="text-2xl">247</p>
</div>✅ Good:
import { StatCard } from '@akanaka-design/components';
<StatCard label="Total Staff" value={247} accent="primary" />There is no autofix; replace the markup manually using StatCard props (label, value, accent, etc.).
akanaka/require-semantic-badge-variants
Scoped to dashboard pages (**/dashboard/**) and to files whose path contains table or compliance (same exemptions as other dashboard rules: report PDF routes and the app style guide page). Keeps status and compliance chips on the RAG semantic system instead of Shadcn layout variants.
Badge variants (Akanaka): default, primary, success, warning, error, info. Use success / warning / error / info for state and compliance labels; avoid secondary and accent (not part of the DS API).
❌ Bad:
<Badge variant="secondary">Compliant</Badge>
<Badge variant="accent">Warning</Badge>
<Badge>Non-Compliant</Badge>
<span className="bg-secondary">In Progress</span>✅ Good:
<Badge variant="success">Compliant</Badge>
<Badge variant="warning">Action Required</Badge>
<Badge variant="error">Non-Compliant</Badge>
<Badge variant="warning">In Progress</Badge>The rule uses static analysis: it suggests a variant from static label text when possible. Dynamic labels (e.g. {row.status}) still need an explicit semantic variant chosen in code.
akanaka/no-hardcoded-colors
Prevents hardcoded color values. Enforces use of Akanaka design tokens.
Detects:
- Hex colors:
#E07A5F,#3B82F6 - RGB/RGBA:
rgb(224, 122, 95),rgba(59, 130, 246, 0.5) - HSL/HSLA:
hsl(12, 70%, 60%),hsla(221, 83%, 53%, 0.8) - Tailwind arbitrary values:
bg-[#E07A5F],text-[rgb(59,130,246)] - Inline styles:
style={{ color: 'red' }}
❌ Bad:
// Hardcoded hex
<div className="bg-[#E07A5F]">Content</div>
// Hardcoded RGB
<div className="bg-[rgb(224,122,95)]">Content</div>
// Inline styles
<button style={{ backgroundColor: '#3B82F6' }}>Click</button>✅ Good:
// Using design tokens
<div className="bg-primary-500">Content</div>
<div className="bg-neutral-700 text-primary-500">Content</div>
<button className="bg-info">Click</button>Smart Suggestions:
The linter calculates color distance and suggests the nearest valid token:
// Input: <div className="bg-[#E07A5F]">
// Error: Hardcoded color "[#E07A5F]". Use bg-primary-500 instead.
// Input: <div className="bg-[#3B82F6]">
// Error: Hardcoded color "[#3B82F6]". Use bg-info instead.
// Input: <div className="bg-[#44403C]">
// Error: Hardcoded color "[#44403C]". Use bg-neutral-700 instead.akanaka/component-exists
Ensures imported components exist in the Akanaka component registry.
❌ Bad:
import { SuperButton } from '@akanaka-design/components';
import { FancyCard } from '@akanaka-design/components';✅ Good:
import { Button } from '@akanaka-design/components';
import { Card, CardTitle, CardContent } from '@akanaka-design/components';Error message includes available components:
Component "SuperButton" does not exist in Akanaka.
Available: Alert, Avatar, Badge, Button, Card...Available Tokens
Colors
Primary (Terracotta):
primary-50, primary-100, primary-200, primary-500, primary-600, primary-700
Neutrals (Warm Stone):
neutral-50, neutral-100, neutral-200, neutral-300, neutral-500, neutral-700, neutral-900
Semantic:
success, warning, error, info
Components
Alert, Avatar, Badge, Button, Card, CardTitle, CardDescription, CardContent, CardFooter, Checkbox, Input, Label, Progress, Select, StatCard, Table, Tabs, Toggle
Integration with Cursor
This config works seamlessly with Cursor:
- Install the package:
pnpm add -D @akanaka-design/eslint-config - Create
.eslintrc.cjsin your project root (see Usage above) - Cursor automatically shows errors in real-time as you type
Tip: add .cursorrules to reinforce design system usage:
# Akanaka Design System Rules
- NEVER use hardcoded colors
- ALWAYS use Tailwind classes with Akanaka tokens
- ONLY import components from @akanaka-design/componentsCI/CD Integration
GitHub Actions
name: Design System Compliance
on:
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- run: pnpm install
- run: pnpm lintTurbo (Monorepo)
If using Turborepo, add to turbo.json:
{
"tasks": {
"lint": {
"cache": false,
"outputs": []
}
}
}Then run:
pnpm turbo lintDevelopment
Running Tests
pnpm test # Run once (includes DZI-29 regression runners via Vitest)
pnpm test:watch # Watch mode
pnpm test:regression # Only dashboard regression runners (StatCard, Badge, tokens, Card)DZI-29 regression fixtures
These guard the dashboard rules added for DZI-29 (AKA-56, AKA-57, AKA-58). Each invalid fixture under tests/fixtures/regression/ is production-shaped JSX that must keep triggering the right rule. Runners lint it with a synthetic path under **/dashboard/** (or table / compliance) so file-scoped rules apply—if logic drifts and violations disappear, CI fails.
There are three fixtures per rule for require-statcard-for-metrics, require-semantic-badge-variants, and prefer-akanaka-tokens-over-shadcn, plus separate coverage for prefer-ds-components. Shared helper: tests/regression-lint-harness.cjs.
Adding a new regression file: add tests/fixtures/regression/dzi-29-<topic>.invalid.tsx, append an entry to the relevant tests/*-regression.runner.cjs fixture list (with a plausible mock page.tsx path), and keep messageIncludes aligned with the rule’s current wording.
Test Coverage
- Hex color detection
- RGB/RGBA detection
- HSL/HSLA detection
- Tailwind arbitrary value detection
- No double-reporting
- Smart token suggestions
- Component registry validation
- Ignores non-Akanaka imports
- Regression fixture for dashboard tokenized card divs (must fail
prefer-ds-components) - DZI-29 regression: three fixtures each for StatCard, semantic
Badge, and Shadcn→Akanaka token rules (dashboard paths)
Publishing
Publish from package directory:
pnpm publish --access publicPre-publish checklist:
pnpm lintpassespnpm testpassesCHANGELOG.mdupdated for the releasepackage.jsonversion bumped appropriatelyfilesincludesREADME.mdandCHANGELOG.md
License
MIT
