Enforcing Tailwind Design Systems with shadcn/lint

Better Stackgo watch the original →

shadcn/lint is an agent-first linter that enforces design system constraints on Tailwind classes, preventing AI agents from injecting arbitrary styles or violating component APIs.

Design System Enforcement

shadcn/lint addresses the lack of strictness in Tailwind CSS by providing an agent-first linter that prevents AI agents from injecting unauthorized styles into components. The tool integrates with Oxlint or ESLint and works by reading existing component definitions, such as CVA (Class Variance Authority) configurations, to determine what styles are permitted. By providing specific error messages when a violation occurs, the linter allows AI agents to correct their own code generation without needing to reference external markdown documentation, which reduces token usage and improves adherence to design standards.

Core Linting Rules

The linter provides six primary rules to maintain codebase consistency:

  • no-restyle: Allows layout-related classes like margin or flex but prevents modifications to padding, color, typography, or effects on components that own their internal spacing.
  • no-raw-colors: Restricts the use of hardcoded colors, forcing the use of theme-defined tokens.
  • no-arbitrary-values: Rejects arbitrary values (e.g., p-[13px]) and suggests the nearest valid token from the design system scale.
  • no-inline-styles: Prevents the use of inline style attributes.
  • no-unknown-classes: Flags classes that do not exist in the project configuration.
  • no-static-classes: Encourages refactoring dynamic template literals to ensure the linter can effectively analyze class usage.

Customization and Limitations

Developers can define component-specific contracts using regex to allow or restrict specific properties, such as permitting typography changes while blocking font-weight modifications. Custom error messages can be configured with placeholders to provide actionable feedback to AI agents. The tool does not currently support plain CSS files or @apply directives, and it cannot trace parent-child selector relationships. It also requires a pre-existing, strictly defined component API to function effectively.

  • #ai
  • #dev-tooling
  • #tailwind

summary by google/gemini-3.1-flash-lite. probably wrong about something. check the source.