Skip to main content

A Dash plugin for integrating TailwindCSS using Dash 3.x hooks

Project description

Dash TailwindCSS Plugin

A plugin for integrating TailwindCSS with Plotly Dash applications using Dash 3.x hooks. Supports both Tailwind CSS v3 and v4.

Tests Coverage Python Version PyPI Ruff GitHub

English | 简体中文

Features

  1. Online Mode: Uses Tailwind CSS CDN for quick setup
  2. Offline Mode: Builds optimized CSS using Tailwind CLI
  3. Automatic Build: Automatically builds Tailwind CSS on app startup
  4. Flexible Configuration: Customizable input/output paths and config files
  5. Automatic Cleanup: Automatically removes generated files to keep directory clean
  6. Node.js Management: Automatically download and use specific Node.js versions
  7. Class-based Architecture: Clean, object-oriented design for better maintainability
  8. Comprehensive Testing: Full test coverage including unit tests, integration tests, and Dash-specific tests
  9. Custom Theme Configuration: Extend Tailwind's default theme with custom colors, spacing, and more
  10. Configurable Cleanup: Control whether intermediate files are cleaned up after build
  11. Tailwind CSS v3 & v4 Support: Supports both Tailwind CSS version 3 and 4

Installation

pip install dash-tailwindcss-plugin

Or for development:

pip install -e .

For development with all dependencies (including test dependencies):

pip install -e .[dev]

Usage

Online Mode (CDN)

from dash import Dash, html
from dash_tailwindcss_plugin import setup_tailwindcss_plugin

# Initialize with CDN mode (default is Tailwind CSS v3)
setup_tailwindcss_plugin(mode="online")

# Or specify Tailwind CSS version (v3 or v4)
# setup_tailwindcss_plugin(mode="online", tailwind_version="4")

app = Dash(__name__)
app.layout = html.Div([
    html.H1("Hello, TailwindCSS!", className="text-3xl font-bold text-blue-600"),
    html.P("This is styled with Tailwind CSS CDN.", className="text-gray-700 mt-4")
])

if __name__ == "__main__":
    app.run(debug=True)

Offline Mode (CLI)

from dash import Dash, html
from dash_tailwindcss_plugin import setup_tailwindcss_plugin

# Initialize with offline mode (default)
setup_tailwindcss_plugin(
    mode="offline",
    tailwind_version="3",  # Specify Tailwind CSS version (v3 or v4)
    content_path=["**/*.py"],  # Files to scan for Tailwind classes
    plugin_tmp_dir="_tailwind",  # Temporary directory for plugin files
    output_css_path="_tailwind/tailwind.css",  # Output CSS file
    config_js_path="_tailwind/tailwind.config.js",  # Tailwind config file
    download_node=True,  # Download Node.js if not found
    node_version="18.17.0"  # Specify Node.js version to download
)

app = Dash(__name__)
app.layout = html.Div([
    html.H1("Hello, TailwindCSS!", className="text-3xl font-bold text-blue-600"),
    html.P("This is styled with locally built Tailwind CSS.", className="text-gray-700 mt-4")
])

if __name__ == "__main__":
    app.run(debug=True)

Custom Plugin Temporary Directory

You can specify a custom temporary directory for plugin files:

from dash import Dash, html
from dash_tailwindcss_plugin import setup_tailwindcss_plugin

# Initialize with custom plugin temporary directory
setup_tailwindcss_plugin(
    mode="offline",
    plugin_tmp_dir="_my_tailwind",  # Custom temporary directory
    input_css_path="_my_tailwind/input.css",
    output_css_path="_my_tailwind/output.css",
    config_js_path="_my_tailwind/config.js"
)

app = Dash(__name__)
app.layout = html.Div([
    html.H1("Custom Directory", className="text-3xl font-bold text-green-600"),
    html.P("This uses a custom temporary directory.", className="text-gray-700 mt-4")
])

if __name__ == "__main__":
    app.run(debug=True)

Control Build Skip Behavior

You can control whether to skip rebuilding if CSS was recently generated:

from dash import Dash, html
from dash_tailwindcss_plugin import setup_tailwindcss_plugin

# Initialize with custom skip build parameters
setup_tailwindcss_plugin(
    mode="offline",
    skip_build_if_recent=True,  # Skip build if CSS was recently generated
    skip_build_time_threshold=10  # Consider CSS recent if generated within 10 seconds
)

app = Dash(__name__)
app.layout = html.Div([
    html.H1("Smart Rebuild", className="text-3xl font-bold text-purple-600"),
    html.P("This uses smart rebuild behavior.", className="text-gray-700 mt-4")
])

if __name__ == "__main__":
    app.run(debug=True)

Custom Theme Configuration

You can extend Tailwind's default theme by providing a custom theme configuration:

from dash import Dash, html
from dash_tailwindcss_plugin import setup_tailwindcss_plugin

# Define custom theme configuration
theme_config = {
    "colors": {
        "brand": {
            "50": "#eff6ff",
            "100": "#dbeafe",
            "200": "#bfdbfe",
            "300": "#93c5fd",
            "400": "#60a5fa",
            "500": "#3b82f6",
            "600": "#2563eb",
            "700": "#1d4ed8",
            "800": "#1e40af",
            "900": "#1e3a8a"
        }
    },
    "borderRadius": {
        "none": "0px",
        "sm": "0.125rem",
        "DEFAULT": "0.25rem",
        "md": "0.375rem",
        "lg": "0.5rem",
        "xl": "0.75rem",
        "2xl": "1rem",
        "3xl": "1.5rem",
        "full": "9999px"
    }
}

# Initialize with custom theme configuration
setup_tailwindcss_plugin(
    mode="offline",
    tailwind_theme_config=theme_config
)

app = Dash(__name__)
app.layout = html.Div([
    html.H1("Custom Theme", className="text-3xl font-bold text-brand-500"),
    html.P("This uses a custom brand color.", className="text-gray-700 mt-4")
])

if __name__ == "__main__":
    app.run(debug=True)

Control Cleanup Behavior

By default, the plugin cleans up intermediate files after building. You can disable this behavior:

from dash import Dash, html
from dash_tailwindcss_plugin import setup_tailwindcss_plugin

# Initialize with cleanup disabled
setup_tailwindcss_plugin(
    mode="offline",
    clean_after=False  # Keep intermediate files after build
)

app = Dash(__name__)
app.layout = html.Div([
    html.H1("No Cleanup", className="text-3xl font-bold text-blue-600"),
    html.P("Intermediate files will be kept after build.", className="text-gray-700 mt-4")
])

if __name__ == "__main__":
    app.run(debug=True)

Project Structure

dash-tailwindcss-plugin/
├── .github/
│   └── workflows/
│       └── test.yml         # GitHub Actions workflow for testing
├── dash_tailwindcss_plugin/
│   ├── __init__.py          # Exports main plugin function   ├── plugin.py            # Main plugin implementation with _TailwindCSSPlugin class   ├── cli.py               # Command-line interface with _TailwindCLI class   └── utils.py             # Utility functions for Node.js management, file operations, etc.
├── tests/
│   ├── README.md            # English test documentation   ├── README-zh_CN.md      # Chinese test documentation   ├── conftest.py          # Pytest configuration fixtures   ├── test_cli.py          # Unit tests for CLI interface   ├── test_dash_integration.py  # Dash end-to-end integration tests   ├── test_plugin.py       # Unit tests for plugin core functionality   └── test_utils.py        # Unit tests for utility functions
├── example_app.py           # Example Dash application
├── requirements-dev.txt     # Development and test dependencies
├── pyproject.toml           # Build configuration
├── pytest.ini               # Pytest configuration
├── ruff.toml                # Ruff configuration (linting)
├── README.md                # English README file
└── README-zh_CN.md          # Chinese README file

Requirements

  • Python 3.8+
  • Dash 3.0+
  • Node.js 12+ (for offline mode, optional if using download_node feature)

How It Works

Online Mode

Offline Mode

  • Uses hooks.setup(priority=3) to build Tailwind CSS on app startup
  • Uses hooks.route(name=built_tailwindcss_link, methods=('GET',), priority=2) to serve the generated CSS file
  • Uses hooks.index(priority=1) to inject the CSS link into the HTML head
  • Automatically installs Tailwind CLI if not present
  • Scans specified files for Tailwind classes to create optimized CSS
  • Automatically downloads Node.js if requested and not found in PATH
  • Automatically cleans up temporary files after build (unless disabled)
  • Smart Rebuild: Skips rebuilding if CSS file was generated within the last 5 seconds
  • Supports both Tailwind CSS v3 and v4 with appropriate CLI packages

Configuration

The plugin accepts the following parameters:

  • mode: "online" or "offline" (default: "offline")
  • tailwind_version: "3" or "4" (default: "3")
  • content_path: Glob patterns for files to scan (default: ["**/*.py"])
  • plugin_tmp_dir: Temporary directory for plugin files (default: "_tailwind")
  • input_css_path: Path to input CSS file (default: "_tailwind/tailwind_input.css")
  • output_css_path: Path to output CSS file (default: "_tailwind/tailwind.css")
  • config_js_path: Path to Tailwind config file (default: "_tailwind/tailwind.config.js")
  • cdn_url: CDN URL for online mode (default: "https://cdn.tailwindcss.com")
  • download_node: Whether to download Node.js if not found (default: False)
  • node_version: Node.js version to download if download_node is True (default: "18.17.0")
  • tailwind_theme_config: Dictionary of custom theme configuration for Tailwind CSS (default: None)
  • clean_after: Whether to clean up generated files after build (default: True)
  • skip_build_if_recent: Whether to skip build if CSS file was recently generated (default: True)
  • skip_build_time_threshold: Time threshold in seconds to consider CSS file as recent (default: 5)

Development

  1. Clone the repository
  2. Install development dependencies: pip install -r requirements-dev.txt
  3. Install in development mode: pip install -e .
  4. Run example: python example_app.py

Running Tests

# Install development dependencies (includes test dependencies)
pip install -r requirements-dev.txt

# Run all tests
python -m pytest tests/

# Run specific test files
python -m pytest tests/test_plugin.py
python -m pytest tests/test_utils.py
python -m pytest tests/test_cli.py
python -m pytest tests/test_dash_integration.py

# Run tests with verbose output
python -m pytest tests/ -v

# Run tests with coverage report
python -m pytest tests/ --cov=dash_tailwindcss_plugin --cov-report=html

See tests/README.md for more detailed information about running tests.

Building the Package

python -m build

This will create both source distribution and wheel files in the dist/ directory.

CLI Tool

The package includes a command-line interface:

dash-tailwindcss-plugin init              # Initialize Tailwind config
dash-tailwindcss-plugin build             # Build CSS manually
dash-tailwindcss-plugin watch             # Watch for changes
dash-tailwindcss-plugin clean             # Clean up generated files

CLI Options

All commands support the following options:

  • --tailwind-version VERSION: Version of Tailwind CSS to use (3 or 4) (default: "3")
  • --content-path INPUT: Glob pattern for files to scan for Tailwind classes. Can be specified multiple times. (default: ["**/*.py"])
  • --plugin-tmp-dir PATH: Temporary directory for plugin files (default: "./_tailwind")
  • --input-css-path PATH: Path to input CSS file (default: "./_tailwind/tailwind_input.css")
  • --output-css-path OUTPUT: Path to output CSS file (default: "./_tailwind/tailwind.css")
  • --config-js-path CONFIG: Path to Tailwind config file (default: "./_tailwind/tailwind.config.js")
  • --tailwind-theme-config JSON: JSON string of custom theme configuration for Tailwind CSS
  • --download-node: Download Node.js if not found in PATH
  • --node-version VERSION: Node.js version to download (if --download-node is used)
  • --clean-after: Clean up generated files after build (only for build command)

Example:

dash-tailwindcss-plugin build --download-node --node-version 18.17.0

Example with multiple content paths:

dash-tailwindcss-plugin build --content-path "**/*.py" --content-path "**/*.js"

Example with custom theme configuration:

dash-tailwindcss-plugin build --tailwind-theme-config "{\"colors\":{\"brand\":{\"500\":\"#3b82f6\"}}}"

Example with Tailwind CSS v4:

dash-tailwindcss-plugin build --tailwind-version 4

Example with custom plugin temporary directory:

dash-tailwindcss-plugin build --plugin-tmp-dir "./my-tailwind" --input-css-path "./my-tailwind/input.css" --output-css-path "./my-tailwind/output.css" --config-js-path "./my-tailwind/config.js"

Architecture

The plugin follows a clean, object-oriented architecture:

Main Classes

  1. _TailwindCSSPlugin (plugin.py): Main plugin class that handles all Tailwind CSS integration
  2. _TailwindCLI (cli.py): CLI tool class that provides command-line interface
  3. Utility Functions (utils.py): Helper functions for Node.js management, file operations, etc.

Entry Points

  • setup_tailwindcss_plugin(): Main entry point for the plugin
  • main(): Entry point for the CLI tool

This design ensures clean separation of concerns and makes the codebase easier to maintain and extend.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dash_tailwindcss_plugin-0.1.6.tar.gz (28.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dash_tailwindcss_plugin-0.1.6-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file dash_tailwindcss_plugin-0.1.6.tar.gz.

File metadata

  • Download URL: dash_tailwindcss_plugin-0.1.6.tar.gz
  • Upload date:
  • Size: 28.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.19

File hashes

Hashes for dash_tailwindcss_plugin-0.1.6.tar.gz
Algorithm Hash digest
SHA256 73385b785f602a9846b5426a1b55363c156466161ee8d05cb3692ecddd2d8b71
MD5 e258c83fa60a1482529fb3665f0aaf55
BLAKE2b-256 5906e8455754b8c8f28b520b7b99a32cdad5369e0ebb89447cd71c8851c36882

See more details on using hashes here.

File details

Details for the file dash_tailwindcss_plugin-0.1.6-py3-none-any.whl.

File metadata

File hashes

Hashes for dash_tailwindcss_plugin-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 b8978d5c2c6ea14dfcef8d296aa5ceed1a755ba2d07bfaef928e1e2af2e92660
MD5 6e0c9343951b4d1f0ae8ddee12e3b302
BLAKE2b-256 244c2ebad775f08be4f1e236efab9cb9170b6b1756a45a83f07ce1ea43a01eab

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page