# elm-review-tailwind

Provides [`elm-review`](https://package.elm-lang.org/packages/jfmengels/elm-review/latest/) rules to sort and organize Tailwind CSS classes in Elm files for improved readability.

## Provided rules

- [`Tailwind.SortAndGroupClasses`](https://package.elm-lang.org/packages/cekrem/elm-review-tailwind/1.0.0/Tailwind-SortAndGroupClasses) - Reports unsorted Tailwind classes and provides automatic fixes to organize them into logical groups.

## Configuration

```elm
module ReviewConfig exposing (config)

import Tailwind.SortAndGroupClasses
import Review.Rule exposing (Rule)

config : List Rule
config =
    [ Tailwind.SortAndGroupClasses.rule
    ]
```

## What it does

This rule organizes Tailwind CSS classes in `Attr.class` declarations by:

1. **Sorting classes into logical groups** (layout, positioning, spacing, typography, colors, etc.)
2. **Splitting long class strings** into multiple `Attr.class` declarations by category
3. **Merging scattered `Attr.class` calls**: when an attribute list has two or more `Attr.class` calls, they're combined, regrouped, and moved ahead of any other attributes (which keep their original relative order)
4. **Handling responsive/state variants** (sm:, md:, hover:, dark:, etc.) correctly, including stacked variants (`dark:hover:bg-gray-700`) and the important modifier (`!mt-4` / `mt-4!`)

### Before

```elm
Html.div
    [ Attr.class "text-gray-700 mt-4 flex p-2 bg-white rounded-lg hover:bg-gray-50 items-center justify-between w-full shadow-sm border border-gray-200"
    ]
    []
```

### After

```elm
Html.div
    [ Attr.class "flex"
    , Attr.class "w-full"
    , Attr.class "items-center justify-between"
    , Attr.class "p-2"
    , Attr.class "mt-4"
    , Attr.class "text-gray-700"
    , Attr.class "bg-white hover:bg-gray-50"
    , Attr.class "border border-gray-200 rounded-lg"
    , Attr.class "shadow-sm"
    ]
    []
```

The rendered HTML produces the exact same classes - multiple `Attr.class` declarations concatenate into a single `class` attribute.

## Class grouping order

Classes are sorted into these groups (in order):

1. Layout & Display (`block`, `flex`, `grid`, `hidden`, `table`, `list-item`, etc.)
2. Positioning (`absolute`, `relative`, `top-*`, `z-*`, etc.)
3. Box Sizing (`box-border`, `box-content`)
4. Container & Sizing (`w-*`, `h-*`, `max-w-*`, etc.)
5. Overflow & Visibility (`overflow-*`, `visible`, `invisible`)
6. Flexbox (`flex-*`, `grow-*`, `shrink-*`, `basis-*`, `order-*`)
7. Grid (`grid-cols-*`, `col-span-*`, etc.)
8. Alignment (`justify-*`, `items-*`, `content-*`, `self-*`, `place-*`)
9. Gap & Spacing (`gap-*`, `space-*`)
10. Padding (`p-*`, `px-*`, `py-*`, etc.)
11. Margin (`m-*`, `mx-*`, `my-*`, etc.)
12. Typography (`text-*` size/alignment, `font-*`, `leading-*`, `align-*`, etc.)
13. Text Color (`text-red-*`, `text-gray-*`, etc.)
14. Background (`bg-*`)
15. Border (`border-*`, `rounded-*`, `divide-*`)
16. Ring & Outline (`ring-*`, `outline-*`)
17. Shadow (`shadow-*`)
18. Opacity & Effects (`opacity-*`)
19. Filters (`blur-*`, `brightness-*`, `filter`, `filter-none`, etc.)
20. Transforms (`scale-*`, `rotate-*`, `translate-*`)
21. Transitions & Animation (`transition-*`, `duration-*`, `animate-*`)
22. Interactivity (`cursor-*`, `select-*`, `pointer-events-*`, `accent-*`, `appearance-*`, etc.)
23. SVG (`fill-*`, `stroke-*`)
24. Screen Readers (`sr-only`, `not-sr-only`)

Note that Alignment (8, flex/grid alignment) is a distinct group from Flexbox (6) and Grid (7) — `flex items-center justify-between` becomes two separate `Attr.class` calls (`flex` in Layout & Display, `items-center justify-between` in Alignment), not one merged call. This keeps grouping fully mechanical: every class always lands in exactly one of the 24 categories above, with no case-by-case judgment calls about what "reads better" combined.

Within each group, classes are sorted alphabetically. Variant prefixes are handled by sorting based on the base class, with this prefix order: unprefixed first, then breakpoints (sm, md, lg, xl, 2xl), then states (hover, focus, active, disabled, or any other single-word variant), then dark mode. Stacked variants (e.g. `dark:hover:bg-gray-700`) are ranked by breakpoint, then dark, then state, regardless of the order the prefixes are written in. The important modifier (`!mt-4` or `mt-4!`) doesn't affect grouping or ordering.

## Try it out

You can try the example configuration above out by running the following command:

```bash
elm-review --template cekrem/elm-review-tailwind/example
```

## AI disclosure

See [AI_DISCLOSURE.md](./AI_DISCLOSURE.md).
