Tailwhip — Tailwind CSS class sorter

PyPI version Test Python Version License: MIT

Tailwhip is a pure Python Tailwind CSS class sorter that works with any HTML or CSS file — including Django templates and other templating languages.

Screenshot of Tailwhip

Why Tailwhip?

The official Prettier plugin for sorting Tailwind classes doesn’t play well with many template languages, such as Django. While there are Prettier plugins that add limited support for Jinja templates, they often require configuration workarounds or restrict what you can do with Prettier.

Tailwhip takes a more pragmatic approach. Instead of trying to parse and understand every possible template syntax, it focuses on sorting Tailwind classes reliably, and ignores class attributes that contain template syntax.

How it works:

  1. It finds all class="" attributes and @apply directives in the given files.
  2. It sorts the contained classes according to the official Tailwind CSS class order.
  3. If a class attribute contains template syntax (e.g., {{ ... }} or {% ... %}), Tailwhip leaves it untouched.

This approach ensures Tailwhip works across diverse environments — Django, Flask, Jinja2, or even custom templating engines — without breaking your templates or requiring complicated setup.

Usage

Tailwhip requires Python 3.11 or later.

$ uvx tailwhip [options] [filepath...]

# Find all .html and .css files in the templates directory
$ uvx tailwhip templates/

# Preview changes
$ uvx tailwhip templates/ -vv

# Actually apply changes
$ uvx tailwhip templates/ --write

# Sort classes in .scss files
$ uvx tailwhip "templates/**/*.scss"

# Standard glob patterns are supported
$ uvx tailwhip "static/**/*.{css,scss}" "templates/**/*.htm[l]"

# Use as a stdin/stdout filter (great for editor integrations!)
$ echo '<div class="p-4 m-2 bg-white">' | uvx tailwhip
<div class="m-2 p-4 bg-white">

# Pipe file content through tailwhip
$ cat template.html | tailwhip > sorted.html

You can also install it with pip and use it as a Python library:

$ pip install tailwhip

$ tailwhip templates/
$ python -m tailwhip templates/

See --help for all options and features.

Editor Integration

Tailwhip works as a STDIN/STDOUT filter, making it easy to integrate with text editors:

Shell:

$ tailwhip < file.html
$ cat file.html | tailwhip > file.html
``````

**Vim/Neovim:**
```vim
" Sort classes in current file
:%!tailwhip

" Sort classes in visual selection
:'<,'>!tailwhip

Emacs:

;; Sort classes in region
(shell-command-on-region (region-beginning) (region-end) "tailwhip" t t)

VSCode: Configure as an external formatter or create a task that pipes selected text through tailwhip.

The stdin mode processes text and returns the result immediately, with no file I/O or configuration needed.

Pre-commit Hook

Tailwhip can automatically sort your Tailwind classes before every commit using pre-commit.

Add a .pre-commit-config.yaml file to your project:

repos:
 - repo: https://github.com/bartTC/tailwhip
   rev: v0.11  # Use the latest release tag
   hooks:
     - id: tailwhip

Customizing File Types

To include additional file types (like JSX, TSX, or template files), add a files pattern:

repos:
  - repo: https://github.com/bartTC/tailwhip
    rev: v0.11
    hooks:
      - id: tailwhip
        files: \.(html|htm|css|jsx|tsx|liquid)$

Configuration

Tailwhip works great out of the box with sensible defaults, but you can customize its behavior to match your project's needs. There are two ways to configure Tailwhip:

Option 1: pyproject.toml

Add a [tool.tailwhip] section to your project's pyproject.toml:

[tool.tailwhip]
# Increase verbosity to see detailed changes
verbosity = 2

# Customize file patterns to include JSX/TSX files
default_globs = [
    "**/*.html",
    "**/*.css",
    "**/*.jsx",
    "**/*.tsx",
]

# Add your custom Tailwind colors
custom_colors = ["brand", "accent", "company"]

# Add template syntax for your templating engine
skip_expressions = ["{{", "{%", "<%", "[[", "]]"]

Option 2: Custom Configuration File

Create a tailwhip.toml file anywhere in your project and pass it via the --configuration flag:

# tailwhip.toml
verbosity = 3

default_globs = [
    "**/*.html",
    "**/*.css",
    "**/*.liquid",  # Shopify Liquid templates
]

custom_colors = ["primary", "secondary", "accent"]

skip_expressions = ["{{", "{%", "<%", "{-"]  # Add Nunjucks syntax

Then use it with:

$ tailwhip templates/ --configuration=tailwhip.toml

Configuration Precedence

Settings are loaded in this order (later sources override earlier ones):

  1. Default values (built into Tailwhip)
  2. pyproject.toml ([tool.tailwhip] section)
  3. Custom config file (via --configuration flag)
  4. CLI arguments (e.g., --write, -v, --quiet)

CLI arguments always take precedence, so you can override any config value on the command line.

Available Configuration Options

For a complete list of all configuration options with detailed explanations, see the default configuration file. It includes:

  • Output settings: verbosity, write_mode
  • File discovery: default_globs
  • Template handling: skip_expressions
  • Sorting behavior: utility_groups, variant_groups
  • Color recognition: tailwind_colors, custom_colors
  • Pattern matching: class_patterns (advanced)

Most users only need to customize custom_colors and occasionally default_globs or skip_expressions. The sorting algorithm is based on Tailwind best practices and rarely needs modification.

Advanced: Custom Pattern Matching

Tailwhip uses configurable patterns to find and sort class attributes across different syntaxes. By default, it supports:

  • HTML class="..." attributes
  • CSS @apply ...; directives

You can add custom patterns for other frameworks (JSX, Vue, Svelte, etc.) by configuring class_patterns in your pyproject.toml or custom config file.

Important: Custom class_patterns replace (not extend) the defaults, just like any other configuration setting. You must include the default HTML and CSS patterns if you want to keep them:

# Example: Add JSX className support while keeping HTML class and CSS @apply
# In pyproject.toml, use [[tool.tailwhip.class_patterns]]
# In custom config file, use [[class_patterns]]

# Keep default: HTML class attribute
[[tool.tailwhip.class_patterns]]
name = "html_class"
regex = '''\bclass\s*=\s*(?P<quote>["'])(?P<classes>.*?)(?P=quote)'''
template = 'class={quote}{classes}{quote}'

# Keep default: CSS @apply directive
[[tool.tailwhip.class_patterns]]
name = "css_apply"
regex = '''@apply\s+(?P<classes>[^;]+);'''
template = '@apply {classes};'

# Add custom: JSX className
[[tool.tailwhip.class_patterns]]
name = "jsx_classname"
regex = '''\bclassName\s*=\s*(?P<quote>["'])(?P<classes>.*?)(?P=quote)'''
template = 'className={quote}{classes}{quote}'

Requirements: - Each pattern must have a (?P<classes>...) named group to capture the classes - The template field uses {classes} and any other named groups from the regex - Additional named groups are optional but must match between regex and template

See the configuration file for more examples and detailed documentation.

Changelog

See CHANGELOG.md for a complete list of changes and version history.

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

Unreleased

Added

  • CI/CD: GitHub Actions workflow for automated documentation deployment
  • Added .github/workflows/deploy-docs.yml for generating and deploying documentation
  • Uses Microdocs to convert README.md and CHANGELOG.md into HTML documentation site
  • Automatically deploys to GitHub Pages on push to main branch
  • Includes comprehensive inline documentation explaining each workflow step
  • Manual workflow dispatch option available from Actions tab

Changed

  • Documentation: Updated documentation URL in pyproject.toml to point to GitHub Pages
  • Changed from GitHub README link to https://barttc.github.io/tailwhip/
  • Provides users with a dedicated documentation site instead of raw markdown

0.11.0 - 2025-11-12

Added

  • Pre-commit Integration: Git pre-commit hook support for automatic class sorting
  • Added .pre-commit-hooks.yaml for seamless pre-commit integration
  • Users can reference tailwhip directly: repo: https://github.com/bartTC/tailwhip
  • Automatically sorts Tailwind classes in HTML and CSS files before each commit
  • Documentation includes setup instructions and customization examples
  • Added pre-commit to dev dependencies

Changed

  • CLI Output: Simplified output messaging for better usability
  • Removed verbose flag hints from normal output (cluttered default experience)
  • Moved dry run warning and completion message to verbose mode only
  • Cleaner default output focuses on essential information

  • Documentation: Added usage examples to CLI help text

  • Examples demonstrate common workflows: single files, multiple files, directories
  • Shows write mode, verbose diff preview, and stdin/stdout usage
  • Improves discoverability of key features for new users

  • Testing: Added test coverage for stdin behavior when no input is provided

  • New test test_no_stdin_and_no_files verifies proper error handling
  • Ensures clean exit with appropriate error message (no traceback)

0.10.1 - 2025-11-07

Fixed

  • Reliability: Fixed crash when no pyproject.toml is found in current or parent directories

0.10.0 - 2025-11-06

Added

  • Editor Integration: STDIN/STDOUT filter mode for text editor integrations
  • Tailwhip now reads from stdin and writes to stdout when no file paths are provided
  • Enables direct integration with Vim/Neovim (:%!tailwhip), Emacs, VSCode, and other editors
  • No configuration or file I/O needed - just pipe text through tailwhip
  • Added comprehensive test suite in test_stdin.py with 4 test cases
  • Updated documentation with editor integration examples for Vim, VSCode, and Emacs

Changed

  • Documentation: Added additional project metadata URLs to pyproject.toml

  • Added direct link to project documentation (README.md)

  • Added direct link to changelog (CHANGELOG.md)
  • Added direct link to bug tracker (GitHub Issues)

  • Refactoring: Moved all_colors computation to configuration module

  • Added all_colors attribute to TailwhipConfig class

  • Computed once during pattern recompilation instead of on every sort
  • Simplified function signatures by removing all_colors parameter passing
  • is_color_utility() and sort_key() now use config.all_colors directly

  • Testing: Simplified test suite for better maintainability

  • Removed redundant integration tests (test_kitchen_sink_example, test_css_apply_advanced)
  • Added focused test_deduplication test for duplicate class handling
  • Updated test documentation to reflect current coverage

0.9.4 - 2025-11-05

Added

  • Development: Claude Code project configuration
  • Added PROJECT.md with development workflow guidelines
  • Added slash commands: /release, /changelog and /verify
  • Configured hooks to enforce workflow: tests → linting → changelog
  • Automated reminders after code changes to ensure quality standards
  • Shared settings in settings.json for all contributors
  • Added .claude/settings.local.json to .gitignore for personal overrides

Changed

  • Performance: File processing now starts immediately when scanning large directories

  • Removed eager materialization of file list in apply_changes()

  • Files are now processed as they are discovered by the generator
  • Significantly reduces startup delay for large codebases

  • Reliability: Added 60-second timeout to file processing

  • Prevents indefinite hangs when processing files

  • as_completed() now uses timeout parameter in apply_changes()

  • Documentation: Restructured comments in configuration arrays

  • All comments in utility_groups and variant_groups now consistently appear above their patterns
  • Clear separation between major groups with blank lines
  • Improved readability and maintainability of configuration structure

0.9.3 - 2025-01-04

Changed

  • Sorting: Position utilities (top, right, bottom, left) now sort clockwise
  • Split combined positioning pattern into separate utility groups
  • Order: top → right → bottom → left (clockwise direction)

0.9.2 - 2025-01-04

Removed

  • Configuration: Removed "primary" from default custom_colors list
  • The default config should not include example custom colors
  • Users should add their own custom colors as needed

Added

  • Tests: Added tests for custom pattern configuration
  • test_custom_pattern_from_pyproject: Tests custom patterns via pyproject.toml
  • test_custom_pattern_from_config_file: Tests custom patterns via custom config file
  • Both tests verify JSX className pattern as example of extensibility
  • Ensures all patterns (HTML, CSS, custom) work correctly together
  • Demonstrates correct TOML syntax for both configuration methods

Changed

  • Documentation: Clarified that class_patterns replace (not extend) defaults
  • Updated README.md with explicit warning about replacement behavior
  • Updated configuration.toml with IMPORTANT note about preserving defaults
  • Updated example.tailwhip.toml with complete example showing default patterns
  • Added JSX example showing how to include defaults when adding custom patterns

0.9.1 - 2025-01-04

Added

  • CI/CD: GitHub Actions workflow for linting

  • Runs ruff check to verify code quality

  • Runs ruff format check to ensure consistent code formatting
  • Added ruff to dev dependencies

  • Documentation: PyPI version badge in README

  • Pattern System: Extensible pattern matching for multiple syntaxes

  • New class_patterns configuration with regex and template support
  • Built-in support for HTML class and CSS @apply
  • Users can add custom patterns for JSX, Vue, Svelte, and other frameworks
  • All patterns use consistent (?P<classes>...) named group requirement
  • Template-based reconstruction using named groups from regex matches

Changed

  • Configuration: Updated example.tailwhip.toml with comprehensive documentation

  • Aligned structure and descriptions with main configuration.toml

  • Added clearer usage examples for common customization scenarios
  • Improved comments and organization for better user guidance

  • Architecture: Unified pattern processing system

  • Replaced separate class_regex and apply_regex with class_patterns list
  • Single process_pattern() function handles all syntax types
  • New Pattern dataclass for compiled regex patterns
  • Compiled patterns stored in config.APPLY_PATTERNS

Removed

  • Deprecated Functions: Removed process_html() and process_css()
  • All functionality now available through process_text()
  • Tests updated to use unified process_text() function

0.9 - 2025-11-04

Added

  • CI/CD: GitHub Actions workflow for automated testing

  • Python matrix testing across versions 3.11, 3.12, 3.13, and 3.14

  • Runs on push and pull requests to main branch
  • Uses uv for fast dependency management

  • Documentation Enhancements

  • CI/CD status badge in README

  • Python version support badge
  • MIT license badge
  • Direct link to CHANGELOG.md from README

  • Testing Infrastructure

  • Comprehensive tests for file writing functionality

  • Edge case coverage for file operations
  • Coverage configuration with proper exclusions

  • Verbosity Levels: New DIFF mode for showing changes

  • Enhanced output options for reviewing modifications
  • Better visibility into what will be changed

Changed

  • Configuration Access: Refactored to use direct attribute access instead of dictionary keys
  • Cleaner, more Pythonic API
  • Better IDE autocomplete support

Fixed

  • Documentation: Corrected README usage example for --configuration flag syntax

Removed

  • Code Cleanup: Removed unused datatypes.py module

0.9b0 - 2025-01-04

Added

  • Configuration System: Complete configuration management with Dynaconf

  • Support for pyproject.toml via [tool.tailwhip] section

  • Support for custom configuration files via --configuration flag
  • Clear configuration precedence: defaults < pyproject.toml < custom config < CLI arguments
  • Comprehensive configuration documentation in configuration.toml with examples and recommendations

  • Configuration Options: New customizable settings

  • verbosity: Control output detail level (0-3)

  • write_mode: Safe dry-run mode by default
  • default_globs: Customize file patterns to process
  • skip_expressions: Add template engine syntax to skip
  • custom_colors: Define custom Tailwind colors from your config
  • utility_groups and variant_groups: Fine-tune sorting behavior (advanced)

  • CLI Enhancements

  • --configuration / -c flag to specify custom config file

  • Improved help text and error messages
  • Configuration validation and error handling

  • Testing Infrastructure

  • Comprehensive CLI and configuration precedence tests

  • Dynamic test fixtures using temporary directories (no stub files in repo)
  • Module docstrings for all test files
  • Configuration reset fixture to prevent test pollution

  • Documentation

  • Complete configuration guide in README.md
  • Examples for pyproject.toml and custom config files
  • Configuration precedence documentation
  • Detailed comments in configuration.toml

Changed

  • Configuration Architecture: Migrated from simple constants to Dynaconf-based system

  • Centralized configuration in configuration.py

  • Dynamic recompilation of regex patterns on config updates
  • Type-safe configuration with TailwhipConfig class

  • Unknown Class Sorting: Unknown classes now sort at the front (before matched patterns)

  • Test Files: Tests now use temporary directories instead of static testdata files

  • Cleaner repository (no stub files)
  • Better test isolation
  • Faster test setup

Fixed

  • Handle UnicodeDecodeError when reading files - now skips unreadable files gracefully
  • Configuration value types properly validated and converted
  • Test pollution between test runs via autouse reset fixture

Internal

  • Simplified pyproject.toml retrieval logic
  • Refactored constants handling with centralized pattern compilation
  • Improved file discovery with generic glob setup
  • Better thread context management for parallel processing
  • Code organization and type improvements

Alpha Status (0.9a1 - 0.9a3)

The initial alpha releases established the core functionality of Tailwhip.

Features

  • Tailwind Class Sorting: Core sorting algorithm based on official Tailwind CSS class ordering

  • Utility class grouping (layout, spacing, typography, visual effects, etc.)

  • Variant sorting (responsive breakpoints, pseudo-classes, state modifiers)
  • Alphabetical sorting within groups

  • Template Engine Support: Automatic detection and skipping of template syntax

  • Support for Django, Jinja2, Liquid, ERB, and other templating languages

  • Classes with template expressions ({{ }}, {% %}, <% %>) are left unchanged

  • File Processing: Batch processing with multiple file types

  • HTML and CSS file support

  • @apply directive sorting in CSS
  • Glob pattern support for file discovery

  • CLI Interface: Command-line tool with essential options

  • Dry-run mode by default (safe preview of changes)

  • --write flag to apply changes
  • Verbosity controls (-v, -vv, -vvv)
  • --quiet mode for minimal output

  • Error Handling: Robust file processing

  • Skip unreadable files (Unicode errors)
  • Skip nonexistent paths gracefully
  • Continue processing on individual file errors

Development Milestones

  • 0.9a1 - Initial release with core sorting functionality
  • 0.9a2 - Bug fixes, improved error handling, and type hint improvements
  • 0.9a3 - Enhanced template syntax handling and documentation updates