eslint-plugin-better-unocss
v0.4.0
Published
ESLint plugin for UnoCSS with tagged template literal support, multiline formatting, and real UnoCSS engine sorting
Maintainers
Readme
eslint-plugin-better-unocss
ESLint plugin for UnoCSS with real engine sorting, tagged template literals, and powerful formatting rules.
Why?
The official @unocss/eslint-plugin only detects class strings in class="..." attributes.
This plugin also detects classes in:
- Tagged templates:
cn`flex items-center` - Function calls:
cn('flex items-center') - Multiline strings with proper formatting
Plus additional rules for conflict detection, unknown class detection, and class restrictions.
Uses the same UnoCSS sorting engine as the official plugin.
Installation
pnpm add -D eslint-plugin-better-unocssQuick Start
// eslint.config.ts
import { configs } from 'eslint-plugin-better-unocss'
export default [
configs.recommended,
]Rules
| Rule | Description | Fixable |
|------|-------------|---------|
| order | Sort classes using UnoCSS engine | Yes |
| no-duplicate-classes | Disallow duplicate classes | Yes |
| no-conflicting-classes | Disallow classes that set the same CSS property | Yes |
| no-unknown-classes | Disallow classes not recognized by UnoCSS | No |
| no-restricted-classes | Disallow specific class patterns | Yes |
| no-unnecessary-whitespace | Normalize whitespace in class strings | Yes |
| enforce-line-wrapping | Enforce consistent multiline formatting | Yes |
Configuration
configs.recommended
Recommended config with sensible defaults:
{
// Stylistic (warn)
'better-unocss/order': 'warn',
'better-unocss/no-unnecessary-whitespace': 'warn',
// Correctness (error)
'better-unocss/no-conflicting-classes': 'error',
'better-unocss/no-duplicate-classes': 'error',
'better-unocss/no-unknown-classes': 'error',
}Manual Configuration
// eslint.config.ts
import { rules } from 'eslint-plugin-better-unocss'
export default [
{
plugins: {
'better-unocss': { rules },
},
rules: {
'better-unocss/order': 'error',
'better-unocss/no-duplicate-classes': 'error',
'better-unocss/no-conflicting-classes': 'error',
'better-unocss/no-unknown-classes': 'error',
'better-unocss/no-unnecessary-whitespace': 'error',
'better-unocss/no-restricted-classes': ['error', {
restrict: ['hidden'],
}],
'better-unocss/enforce-line-wrapping': ['error', {
classesPerLine: 1,
printWidth: 80,
indent: 2,
group: 'newLine',
}],
},
},
]Features
Tagged Template Literals
// Fully supported
cn`flex items-center gap-4`
tw`hover:bg-red-500 focus:ring`
clsx`p-4 mt-2`Function Calls
// All arguments are linted
cn('flex items-center')
clsx('p-4', condition && 'mt-2')
cva('base-class', { variants: { size: { sm: 'text-sm' } } })Variant Groups
// Handled correctly
cn`hover:(bg-red-500 text-white) dark:(bg-gray-800)`Multiline Formatting
// Before
cn`flex items-center justify-between gap-4 px-8 py-4`
// After (with enforce-line-wrapping)
cn`
flex
items-center
justify-between
gap-4
px-8
py-4
`Conflict Detection
// Error: Conflicting classes for display: flex, block
cn`flex block items-center`
// OK: Different variants = no conflict
cn`flex hover:block`Framework Support
| Framework | Status | |-----------|--------| | ES/JS/TS | Supported | | Vue SFC | Supported | | JSX/TSX | Supported |
Vue Example
<template>
<!-- Static class -->
<div class="flex items-center" />
<!-- Dynamic binding -->
<div :class="'flex items-center'" />
<div :class="{ 'flex': true, 'hidden': isHidden }" />
</template>
<script setup>
// Script expressions
const classes = cn`flex items-center`
</script>JSX Example
// Static className
<div className="flex items-center" />
// Expression
<div className={cn`flex items-center`} />
<div className={cn('flex', condition && 'hidden')} />Supported Callees
Out of the box, the plugin detects:
cn,clsx,classnames,cva,tvtwMerge,twJoin,ccclass,classNameattributes
Custom selectors can be configured per-rule.
Conflicts with Official Plugin
If you use both plugins, disable the official order rule:
{
rules: {
'unocss/order': 'off',
}
}Both use the same UnoCSS engine, so keeping both causes circular fixes.
TypeScript Support
Full TypeScript support with exported types:
import type {
BetterUnocssRules,
OrderOptions,
EnforceLineWrappingOptions,
NoRestrictedClassesOptions,
// ... other option types
} from 'eslint-plugin-better-unocss'License
Credits
Inspired by eslint-plugin-better-tailwindcss.
