eslint-plugin-tailwindcss icon indicating copy to clipboard operation
eslint-plugin-tailwindcss copied to clipboard

[Feature request] Prevent unknown classes (that follow Tailwind convention)

Open nicooprat opened this issue 1 year ago • 6 comments

Is your feature request related to a problem? Please describe. Example: in our team, some developers keep confusing gray and grey.

Describe the solution you'd like Would be cool to report bg-gray-100 as an error because it follows Tailwind convention but doesn't exist.

Describe alternatives you've considered

  • We'd rather not duplicate the entries in the theme to prevent confusion & bloat in every tools (like IDE autocomplete, Storybook, ...).
  • I thought about using no-restricted-syntax ESLint rule but it won't cover every case (Vue classes, @apply tags, ...)

Additional context Add any other context or screenshots about the feature request here.

nicooprat avatar Oct 14 '24 15:10 nicooprat

👋 @nicooprat! You should be able for that tailwindcss/no-custom-classname rule for that.

kachkaev avatar Oct 21 '24 22:10 kachkaev

Hi, thanks for the suggestion, I tried a few regexes with the whitelist option to match everything BUT not *-gray-*, without luck. I guess something like a blacklist would be easier in my case.

nicooprat avatar Oct 22 '24 12:10 nicooprat

I'm currently refactoring a project to use semantic tokens instead of scale values e.g. text-red-500text-critical. I think it's a good use case for blacklist or similar.

@kachkaev Unless there's a way to configure this behaviour using the existing API?

blue-infinex avatar Mar 18 '25 22:03 blue-infinex

@blue-infinex I see two options here:

  1. You can remove colors like text-red-500 from your theme. tailwindcss/no-custom-classname will flag them but also all existing instances will stop working (all replacements will need to happen in one go).

  2. You can create a custom ESLint rule or configure no-restricted-syntax. Simplified example:

    {
      selector: `Literal[value=/(bg|border)-(red|green)-500/]`,
      message: "Please use a theme color instead"
    }
    

    With this approach, you can start by marking existing cases (// eslint-disable-next-line -- TODO: fix) and then gradually fix them when there is time.

kachkaev avatar Mar 19 '25 09:03 kachkaev

Ah, okay! The no-restricted-syntax approach seems like the way to go. Thanks for the context, and for responding so quickly. I really appreciate it ✨

blue-infinex avatar Mar 19 '25 11:03 blue-infinex

For Vue, this is what Cursor suggested:

'vue/no-restricted-syntax': [
  {
    selector:
      'VAttribute[key.name="class"][value.value=/gray/] , VAttribute[directive=true][key.argument.name="class"] > VExpressionContainer:matches([value=/gray/], ArrayExpression > Literal[value=/gray/], ObjectExpression > Property > Literal[value=/gray/])',
    message: 'Use "grey" instead of "gray" because it does not exist in our Tailwind config.',
  }
]
Image

Hope it helps!

nicooprat avatar Mar 20 '25 08:03 nicooprat