An open API service indexing awesome lists of open source software.

https://github.com/agolosnichenko/eslint-plugin-tailwind-grouping

ESLint plugin to group and organize Tailwind CSS classes
https://github.com/agolosnichenko/eslint-plugin-tailwind-grouping

code-style eslint eslint-plugin formatting tailwind tailwindcss

Last synced: 16 days ago
JSON representation

ESLint plugin to group and organize Tailwind CSS classes

Awesome Lists containing this project

README

          

# ESLint Plugin: Tailwind Grouping

An ESLint plugin that automatically groups and organizes Tailwind CSS classes into semantic categories, improving
readability and maintainability of your React/JSX code.

## 📋 Table of Contents

- [Problem](#problem)
- [Solution](#solution)
- [Installation](#installation)
- [Usage](#usage)
- [Configuration](#configuration)
- [Examples](#examples)
- [Development](#development)

## Problem

Large Tailwind className strings are difficult to read and maintain:

```jsx

```

## Solution

The plugin automatically transforms long className strings into organized, commented groups using `clsx`:

```jsx

```

## Installation

```bash
npm install --save-dev eslint-plugin-tailwind-grouping
# or
yarn add -D eslint-plugin-tailwind-grouping
# or
pnpm add -D eslint-plugin-tailwind-grouping
```

## Usage

### ESLint Configuration (Flat Config - ESLint 9+)

```javascript
// eslint.config.js
import tailwindGrouping from 'eslint-plugin-tailwind-grouping';

export default [
{
plugins: {
'tailwind-grouping': tailwindGrouping
},
rules: {
'tailwind-grouping/group-classes': ['warn', {
threshold: 5,
include: ['**/*.tsx', '**/*.jsx'],
exclude: ['**/*.test.tsx']
}]
}
}
];
```

### ESLint Configuration (Legacy)

```json
{
"plugins": [
"tailwind-grouping"
],
"rules": {
"tailwind-grouping/group-classes": [
"warn",
{
"threshold": 5
}
]
}
}
```

### Using with Prettier

This plugin is compatible with Prettier. Make sure to run ESLint with `--fix` flag:

```bash
eslint --fix .
```

## Configuration

### Options

```typescript
{
// Minimum number of classes required to trigger transformation
// Default: 0
threshold?: number;

// Glob patterns for files to include
// Default: [] (all files)
include?: string[];

// Glob patterns for files to exclude
// Default: [] (no exclusions)
exclude?: string[];

// Custom mapping of groups to class patterns
// Default: DEFAULT_GROUP_MAPPING
mapping?: {
[groupName: string]: string[];
};

// Custom order of groups
// Default: ['Size', 'Layout', 'Spacing', 'Border', 'Background', 'Text', 'Effects', 'Others']
groupOrder?: string[];

// Name of the utility function to use
// Default: 'clsx'
utilityFunction?: string;

// Whether to include group name comments in the output
// Default: true
showGroupNames?: boolean;

// Comment template for group names
// Can be a preset name or a custom template string with variables
// Default: "// {groupName}"
// Presets: 'line', 'block', 'jsdoc', 'bracket', 'numbered', 'verbose'
// Variables: {groupName}, {index}, {count}
commentTemplate?: string;

// Sorting order for classes within each group
// Default: "no-sort"
// Options: 'no-sort' | 'asc' | 'desc' | 'official'
order?: 'no-sort' | 'asc' | 'desc' | 'official';
}
```

### Example: Custom Mapping

```javascript
{
"tailwind-grouping/group-classes":
["warn", {
"threshold": 3,
"mapping": {
"Size": ["w-*", "h-*", "min-w-*", "max-w-*"],
"Colors": ["bg-*", "text-*", "border-*"],
"Spacing": ["p-*", "m-*", "gap-*"],
"Others": []
},
"groupOrder": ["Size", "Colors", "Spacing", "Others"]
}]
}
```

### Example: Custom Utility Function

```javascript
{
"tailwind-grouping/group-classes":
["warn", {
"utilityFunction": "cn" // Use shadcn/ui's cn function
}]
}
```

### Example: Without Group Name Comments

If you prefer cleaner output without the group name comments, you can disable them:

```javascript
{
"tailwind-grouping/group-classes":
["warn", {
"showGroupNames": false
}]
}
```

**Output with `showGroupNames: false`:**

```jsx


Content

```

**Output with `showGroupNames: true` (default):**

```jsx


Content

```

### Example: Custom Comment Templates

Customize how group comments appear using templates with variables or presets:

#### Using Preset Templates

```javascript
{
"tailwind-grouping/group-classes": ["warn", {
"commentTemplate": "block" // Use block comment style
}]
}
```

**Available Presets:**
- `line`: `// {groupName}` (default)
- `block`: `/* {groupName} */`
- `jsdoc`: `/** {groupName} **/`
- `bracket`: `// [{groupName}]`
- `numbered`: `// {index}. {groupName}`
- `verbose`: `// {groupName} ({count} classes)`

#### Using Custom Templates

Create your own templates with these variables:
- `{groupName}`: Name of the group (e.g., "Size", "Spacing")
- `{index}`: 1-based position of the group
- `{count}`: Number of classes in the group

```javascript
{
"tailwind-grouping/group-classes": ["warn", {
"commentTemplate": "// {index}. {groupName} ({count})"
}]
}
```

**Example outputs:**

```jsx
// With commentTemplate: "/* {groupName} */"

// With commentTemplate: "// {index}. {groupName}"

// With commentTemplate: "// {groupName} ({count})"

// With commentTemplate: "// [{index}] {groupName} - {count} classes"


```

### Example: Class Sorting

You can control how classes are sorted within each group:

```javascript
{
"tailwind-grouping/group-classes": ["warn", {
"order": "asc" // Sort alphabetically A-Z
}]
}
```

**Options:**
- `"no-sort"` (default): Preserve original order
- `"asc"`: Sort alphabetically A-Z
- `"desc"`: Sort alphabetically Z-A
- `"official"`: Use Tailwind's official class ordering (same as prettier-plugin-tailwindcss)

**Example output with `order: "asc"`:**

```jsx


```

**Note:** The plugin automatically removes duplicate classes, keeping only the first occurrence.

## Examples

### Before

```jsx


Content

```

### After (with threshold: 3)

```jsx


Content

```

### Handling Modifiers

The plugin preserves all Tailwind modifiers (responsive, state, dark mode, etc.):

```jsx
// Input
className = "md:flex lg:grid hover:bg-blue-500 dark:bg-gray-900"

// Output
className = {
clsx(
// Layout
"md:flex lg:grid",
// Background
"hover:bg-blue-500 dark:bg-gray-900"
)
}
```

### Handling Arbitrary Values

Arbitrary values are properly grouped:

```jsx
// Input
className = "w-[500px] h-[calc(100vh-80px)] bg-[#ff0000]"

// Output
className = {
clsx(
// Size
"w-[500px] h-[calc(100vh-80px)]",
// Background
"bg-[#ff0000]"
)
}
```

## Development

### Setup

```bash
# Install dependencies
npm install

# Build the plugin
npm run build

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Lint the code
npm run lint
```

### Running Tests

```bash
npm test
```

### Testing Locally

To test the plugin in a project before publishing:

```bash
# In the plugin directory
npm link

# In your project directory
npm link eslint-plugin-tailwind-grouping
```

### Design Principles

- **Immutability**: All domain objects are immutable
- **Single Responsibility**: Each class has one clear purpose
- **Dependency Injection**: Services receive dependencies via constructor
- **Testability**: Pure business logic separated from infrastructure
- **Type Safety**: Full TypeScript coverage with strict mode

## Contributing

Contributions are welcome! Please ensure:

1. All tests pass (`npm test`)
2. Code follows the existing architecture
3. New features include tests
4. TypeScript types are properly defined

## License

MIT

## Links

- [GitHub Repository](https://github.com/agolosnichenko/eslint-plugin-tailwind-grouping)
- [Issue Tracker](https://github.com/agolosnichenko/eslint-plugin-tailwind-grouping/issues)
- [Tailwind CSS Documentation](https://tailwindcss.com)
- [ESLint Documentation](https://eslint.org)