ESLint Plugin

ESLint plugin for Nord Design System - enforces logical CSS selectors, assists with migration from legacy classes, and integrates Tailwind best practices.

The @nordhealth/eslint-plugin helps you:

  • Enforce logical CSS properties for better RTL/LTR support
  • Migrate from legacy CSS with auto-fixable rules
  • Follow Tailwind best practices with integrated rules from better-tailwindcss

Installation

Copy code
npm install @nordhealth/eslint-plugin --save-dev

Usage

The plugin provides several preset configurations. Add one to your eslint.config.js:

Copy code
import nordPlugin from '@nordhealth/eslint-plugin'

export default [
  // Recommended: Nord rules + Tailwind best practices
  nordPlugin.configs.recommended,

  // For Vue projects (includes Vue parser)
  nordPlugin.configs.vue,
]

Available Configs

ConfigDescriptionIncluded Rules
recommendedNord + Tailwind rules (warnings)@nordhealth/logical-selectors, @nordhealth/no-unknown-legacy-classes, better-tailwindcss rules
recommended-errorSame as above but as errors@nordhealth/logical-selectors, @nordhealth/no-unknown-legacy-classes, better-tailwindcss rules
nordNord rules only (warnings)@nordhealth/logical-selectors, @nordhealth/no-unknown-legacy-classes
nord-errorNord rules only (errors)@nordhealth/logical-selectors, @nordhealth/no-unknown-legacy-classes
vueRecommended + Vue parser@nordhealth/logical-selectors, @nordhealth/no-unknown-legacy-classes, better-tailwindcss rules, Vue parser
vue-errorVue config with errors@nordhealth/logical-selectors, @nordhealth/no-unknown-legacy-classes, better-tailwindcss rules, Vue parser

Nord Rules

Enforces logical CSS properties over physical ones for better RTL/LTR support. Auto-fixable.

Copy code
<!-- Bad -->
<div class="n:pl-m n:mr-l n:border-l">

<!-- Good -->
<div class="n:p-is-m n:m-ie-l n:border-is">

Converts physical directions to logical equivalents:

PhysicalLogicalDescription
pl/prp-is/p-iePadding inline-start/end
ml/mrm-is/m-ieMargin inline-start/end
pt/pbp-bs/p-bePadding block-start/end
mt/mbm-bs/m-beMargin block-start/end
left/rightinset-is/inset-iePosition inline-start/end
top/bottominset-bs/inset-bePosition block-start/end
border-l/border-rborder-is/border-ieBorder inline-start/end
rounded-tlrounded-ssBorder radius start-start
rounded-trrounded-seBorder radius start-end
rounded-blrounded-esBorder radius end-start
rounded-brrounded-eeBorder radius end-end

Migrates deprecated Nord CSS classes (n-*) to their Tailwind equivalents (n:*). Auto-fixable.

This rule is off by default. Enable it during migration, then disable when complete. See the Migration Guide for details.
Copy code
<!-- Bad -->
<div class="n-padding-m n-margin-l n-color-text-weak">

<!-- Good (auto-fixed) -->
<div class="n:p-m n:m-l n:text-weak">

Available categories:

CategoryDescription
spacingMargin, padding, gap classes
bordersBorder width, color, radius classes
typographyFont size, weight, family, line-height
colorsText, background, status colors
layoutFlex, grid, alignment, container
componentsForm elements, icons
utilitiesShadows, z-index, transitions, misc

Configuration examples:

Copy code
// Enable only specific categories
"@nordhealth/no-legacy-classes": ["warn", {
  categories: ["spacing", "colors"]
}]

// Disable specific categories (enable all others)
"@nordhealth/no-legacy-classes": ["warn", {
  disabledCategories: ["components"]
}]

Flags n-* classes that aren't part of the Nord CSS Framework. This rule helps you:

  • Catch typos in class names (e.g., n-maring-m instead of n-margin-m)
  • Identify deprecated classes that have been removed from the framework
  • Find custom classes that may need to be migrated or replaced
This rule is useful for all legacy CSS users to ensure you're only using valid Nord classes. It works regardless of whether you're planning to migrate to Tailwind.
Copy code
<!-- These will be flagged -->
<div class="n-maring-m">          <!-- typo: should be n-margin-m -->
<div class="n-padding-medium">    <!-- invalid: should be n-padding-m -->
<div class="n-custom-class">      <!-- unknown: not a Nord class -->

<!-- These are valid Nord classes -->
<div class="n-margin-m n-padding-l n-color-text">

Disable this rule if needed:

Copy code
rules: {
  "@nordhealth/no-unknown-legacy-classes": "off"
}

Tailwind Rules

The plugin includes the recommended rules from eslint-plugin-better-tailwindcss:

  • Consistent class ordering - Ensures classes are in a consistent order
  • No duplicate classes - Prevents accidentally duplicating classes
  • No conflicting classes - Catches classes that conflict with each other
  • Shorthand enforcement - Suggests shorthand classes where possible
  • Canonical classes - Enforces canonical Tailwind class names
For the full list of rules and configuration options, see the eslint-plugin-better-tailwindcss documentation.

Enabling no-unknown-classes

The better-tailwindcss/no-unknown-classes rule is not enabled by default because it requires project-specific configuration:

Copy code
import nordPlugin from '@nordhealth/eslint-plugin'

export default [
  nordPlugin.configs.recommended,
  {
    settings: {
      'better-tailwindcss': {
        entryPoint: './path/to/your/tailwind.css'
      }
    },
    rules: {
      'better-tailwindcss/no-unknown-classes': 'warn'
    }
  }
]

Custom Configuration

You can customize individual rules:

Copy code
import nordPlugin from '@nordhealth/eslint-plugin'

export default [
  nordPlugin.configs.recommended,
  {
    rules: {
      // Enable migration rules
      '@nordhealth/no-legacy-classes': ['warn', {
        categories: ['spacing', 'borders', 'colors', 'utilities']
      }],

      // Change severity
      '@nordhealth/logical-selectors': 'error',
    }
  }
]

Class Detection

The plugin detects classes across multiple frameworks and patterns:

Supported frameworks:

FrameworkAttributes detected
HTML/Reactclass, className
Vueclass, :class, v-bind:class
Svelteclass, class:directive
Angular[class], [ngClass], [class.name]
Astroclass, class:list

Supported utility functions:

FunctionLibrary
clsx, classnames, classNamesclsx / classnames
cn, cxCommon aliases
cvaclass-variance-authority
tvtailwind-variants
twMerge, twJointailwind-merge

This means rules will work in code like:

Copy code
// All of these are detected
<div className="n:p-m n:text-default" />
<div className={cn("n:p-m", condition && "n:text-weak")} />
<div className={clsx("n:flex", "n:gap-m")} />

const buttonVariants = cva("n:px-m n:py-s", {
  variants: { size: { lg: "n:px-l n:py-m" } }
})

Was this page helpful?

Yes No

We use this feedback to improve our documentation.