---
slug: "tx"
source_type: "readme"
source_url: "https://cdn.jsdelivr.net/gh/landfolk/tx@main/README.md"
repo: "https://github.com/landfolk/tx"
source_file: "README.md"
branch: "main"
---
# tx

Readable Tailwind at compile time. `tx` replaces `className`, adds grouping
syntax, and compiles to plain Tailwind classes with zero runtime styling cost.

Battle-tested in production at Landfolk.com.

## Why tx

- **Readable**: group variants instead of repeating prefixes.
- **Composable**: arrays and conditionals are built-in; no `clsx`/`classnames`.
- **Safe**: ESLint auto-fixes ordering and can validate classes against your
  Tailwind config.
- **Fast**: SWC transform + Tailwind transformer, no runtime cost.

## How it works

- `tx` is a JSX prop + template tag, compiled at build time.
- SWC plugin rewrites `tx` → `className` and expands arrays/conditionals.
- Grouping syntax expands to plain Tailwind classes before shipping.
- ESLint plugin sorts, groups, and validates classes against your Tailwind config.

## Readable Tailwind

**Before** (hard to scan):

```tsx
<div className="text-sm hover:text-white hover:bg-forest-800 sm:text-base sm:leading-6" />
```

**After** (grouped + compact):

```tsx
<div tx="text-sm hover:(text-white bg-forest-800) sm:(text-base leading-6)" />
```

## Conditional styles without helpers

```tsx
<div
  tx={[
    tx`p-4 rounded-lg`,
    isActive && tx`bg-forest-800 text-white`,
    size === 'lg' ? tx`text-lg` : tx`text-sm`,
  ]}
/>
```

No more string joins or `clsx` wrappers.

## Migration tip

- Replace `className=` with `tx=` in JSX.
- Run your lint task with `--fix` to auto-group/sort classes and catch invalid ones.

## ESLint auto-fixes grouping + order

Input:

```tsx
<div tx="hover:bg-forest-800 font-medium hover:text-white font-medium sm:leading-6 sm:text-base" />
```

Auto-fixed:

```tsx
<div tx="font-medium hover:(bg-forest-800 text-white) sm:(text-base leading-6)" />
```

Invalid classes are flagged when you wire in your Tailwind config:

```tsx
<div tx="text-sm invalid-class" />
// eslint: unknown Tailwind class "invalid-class"
```

With `settings.tx.tailwindConfig`, invalid classes are flagged so you only use
classes that exist in your config.

## Packages

- `@landfolk/tx` — class expansion, Tailwind transformer, conflict checker, types
- `@landfolk/eslint-plugin-tx` — class ordering + validation rule
- `@landfolk/swc-plugin-tx` — SWC transform (Next.js)

## Quick start

See the docs:

- [docs/README.md](https://github.com/landfolk/tx/blob/HEAD/docs/README.md)

## Examples

- `examples/nextjs-smoke` minimal Next.js integration and CI smoke build

## Notes

- SWC plugin is pinned to Next.js **16.1.5**.
- Versioning: v1.x → Next.js 14.2.x, v2.x → Next.js 15.x, v3.x → Next.js 16.x.
