PHPackages                             dxgx/blade-tailwind-extract - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. dxgx/blade-tailwind-extract

ActiveLibrary[Templating &amp; Views](/categories/templating)

dxgx/blade-tailwind-extract
===========================

Extract Tailwind CSS classes to reduce Livewire wire transfer size

v2.3.0(1w ago)058↓20.8%MITPHPPHP ^8.1

Since May 18Pushed 1w agoCompare

[ Source](https://github.com/dxgx/blade-tailwind-extract)[ Packagist](https://packagist.org/packages/dxgx/blade-tailwind-extract)[ RSS](/packages/dxgx-blade-tailwind-extract/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)Dependencies (12)Versions (18)Used By (0)

Blade Tailwind Extract - Tailwind Class Extractor for Laravel
=============================================================

[](#blade-tailwind-extract---tailwind-class-extractor-for-laravel)

[![Latest Version on Packagist](https://camo.githubusercontent.com/c4abbd534c9c770c55f69db5cba2c0a4b7e08dd1c9f1c601508654fce7ae2d6b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f647867782f626c6164652d7461696c77696e642d657874726163742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/dxgx/blade-tailwind-extract)[![Total Downloads](https://camo.githubusercontent.com/2545cd05a1a2a3efa3ab9e65bb1565c111421ffcf68d3429de5b228c627d0fae/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f647867782f626c6164652d7461696c77696e642d657874726163742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/dxgx/blade-tailwind-extract)[![License](https://camo.githubusercontent.com/a593b86a8c95e8b32eea9087a8f9eb75ad02f329d585d2f74f1d88fe637b4987/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f647867782f626c6164652d7461696c77696e642d657874726163742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/dxgx/blade-tailwind-extract)

A Laravel package that dramatically reduces Livewire component wire transfer sizes by extracting long Tailwind CSS class strings into short, reusable CSS class names. Perfect for applications with large lists of Livewire components.

The Problem
-----------

[](#the-problem)

When using Livewire with Tailwind CSS, long class strings in Blade templates get transferred over the wire on every component update:

```

```

With 100 items in a list, this verbose markup significantly impacts performance.

The Solution
------------

[](#the-solution)

Blade Tailwind Extract extracts your Tailwind classes into a CSS file using `@apply`, replacing them with short class names:

**Development Mode (Injected):**

```

```

**Production Mode (Extracted):**

```

```

**Generated CSS:**

```
.TW-a40f-card-wrapper {
    @apply flex flex-col gap-2 p-4 bg-white rounded-lg shadow-md;
}
```

The `a40f` hash is derived from the file path, ensuring no conflicts between files.

Features
--------

[](#features)

- ✅ **Reduces Livewire wire payload** - Short class names instead of verbose Tailwind strings
- ✅ **Automated class identification** - Wrap command finds and marks repeated class lists
- ✅ **Intelligent deduplication** - Identical class lists share the same wrapper name
- ✅ **Comprehensive pattern support** - Works with `class=""`, `wire:class=""`, `:class` (static &amp; ternary), `x-bind:class`, `@class([])` (simple &amp; conditional)
- ✅ **Bidirectional** - Extract for production, restore for development
- ✅ **Safe** - Reserved classes like `group`, `group/`, and `peer` are automatically skipped with informative warnings
- ✅ **Collision-free** - File-based hashing prevents class name conflicts
- ✅ **Pattern matching** - Process specific files or entire directories
- ✅ **Configurable** - Customize prefix, hash length, output path, and more

Installation
------------

[](#installation)

Install via Composer as a dev dependency (this is a development tool, not needed in production):

```
composer require dxgx/blade-tailwind-extract --dev
```

Publish the configuration file (optional):

```
php artisan vendor:publish --tag=blade-tailwind-extract-config
```

Usage
-----

[](#usage)

### Quick Start: 3-Step Workflow

[](#quick-start-3-step-workflow)

1. **Wrap** - Automatically identify and mark class lists with semantic names
2. **Extract** - Convert marked classes into compact CSS
3. **Restore** - Bring back inline classes for editing

### Wrap Classes (Preparation Step)

[](#wrap-classes-preparation-step)

Before extraction, use the wrap command to automatically identify and mark repeated Tailwind class lists with semantic wrapper names. This helps you see which classes will be extracted and ensures consistent naming for identical class lists.

```
# Wrap classes in a specific file
php artisan dg:blade-tailwind:wrap resources/views/components/card.blade.php

# Wrap classes in an entire directory (recursive)
php artisan dg:blade-tailwind:wrap ./resources/views/livewire

# Wrap classes using a pattern
php artisan dg:blade-tailwind:wrap "*preview*"
php artisan dg:blade-tailwind:wrap "*card*.blade.php"

# Wrap multiple files or patterns (comma-separated)
php artisan dg:blade-tailwind:wrap "card.blade.php,list.blade.php"
php artisan dg:blade-tailwind:wrap "*preview*,*card*"

# Wrap all files in search_path (with confirmation prompts)
php artisan dg:blade-tailwind:wrap

# Skip confirmations for automated workflows
php artisan dg:blade-tailwind:wrap --yy

# Preview changes without modifying files
php artisan dg:blade-tailwind:wrap "*preview*" --dry-run

# Customize minimum class count (default: 3)
php artisan dg:blade-tailwind:wrap components/card.blade.php --min=4

# Skip class lists containing specific prefix (default: TW)
php artisan dg:blade-tailwind:wrap components/card.blade.php --skip-prefix=CUSTOM
```

**What it does:**

- Scans for class lists with 3+ classes (configurable via `--min`)
- Automatically deduplicates: identical class lists get the same wrapper name
- Generates semantic names: `__adjective-noun-number__` (e.g., `__happy-cat-1__`)
- Skips patterns that should never be extracted: `__`, `material-symbols-outlined`, `TW-`
- Shows summary of changes with occurrence counts

**Before wrapping:**

```
Item 1
Item 2
Button
```

**After wrapping:**

```
Item 1
Item 2
Button
```

Notice how identical class lists share the same wrapper name (`happy-cat-1`), while different lists get unique names.

Supported Class Attribute Patterns
----------------------------------

[](#supported-class-attribute-patterns)

The wrap command supports all major Blade/Livewire/Alpine.js class attribute patterns:

### 1. Static `class` Attribute

[](#1-static-class-attribute)

Standard HTML class attribute:

```

Content

Content
```

### 2. Livewire `wire:class` Attribute

[](#2-livewire-wireclass-attribute)

Livewire's reactive class binding:

```

Content

Content
```

### 3. Alpine.js `:class` with Static Classes

[](#3-alpinejs-class-with-static-classes)

Dynamic class binding with static string:

```

Click

Click
```

### 4. Alpine.js `:class` with Ternary Expression

[](#4-alpinejs-class-with-ternary-expression)

Conditional class switching with ternary operator:

```

    Toggle

    Toggle

```

### 5. Alpine.js `x-bind:class` Attribute

[](#5-alpinejs-x-bindclass-attribute)

Explicit Alpine binding syntax:

```

Content

Content
```

### 6. Blade `@class` Directive (Simple Array)

[](#6-blade-class-directive-simple-array)

Blade's class directive with simple string:

```

Item

Item
```

### 7. Blade `@class` Directive (Conditional Array)

[](#7-blade-class-directive-conditional-array)

Blade's class directive with conditional classes:

```

 !$isEnabled,
    'text-blue-500 hover:text-blue-600 hover:bg-blue-50' => $isEnabled
])>Action

 !$isEnabled,
    '__kind-dog-10__ text-blue-500 hover:text-blue-600 hover:bg-blue-50 __' => $isEnabled
])>Action
```

### 8. Combined Static and Dynamic Classes

[](#8-combined-static-and-dynamic-classes)

Elements with both static `class` and dynamic `:class` attributes (wrapped independently):

```

    Toggle

    Toggle

```

*Note: In this example, the ternary branches have only 2 classes each (below the default minimum of 3), so they aren't wrapped. The static `class` attribute with 4 classes is wrapped.*

### Pattern Behavior Summary

[](#pattern-behavior-summary)

- **All patterns** respect the minimum class count (default: 3, configurable via `--min`)
- **Identical class lists** across any pattern type share the same wrapper name
- **Already wrapped** class lists are skipped (won't double-wrap)
- **Protected patterns** (containing `__`, `material-symbols-outlined`, or starting with `TW-`) are never wrapped
- **Ternary expressions** have both branches examined and wrapped independently if they meet the threshold
- **Conditional arrays** in `@class` have all string values examined and wrapped independently
- **Static and dynamic** attributes on the same element are processed independently

### Extract Classes (Development → Production)

[](#extract-classes-development--production)

The `target` parameter accepts multiple formats:

**0. No target (processes all files in search\_path with confirmation):**

```
# Prompts for confirmation before processing all .blade.php files
php artisan dg:blade-tailwind:extract

# Shows:
# 1. First confirmation: "Are you sure you want to process X file(s)?"
# 2. List of files to be processed (max 50 shown)
# 3. Second confirmation: "Proceed with extract operation?"
# Cancel at any prompt to abort
```

**1. Directory (processes all .blade.php files recursively):**

```
php artisan dg:blade-tailwind:extract ./resources/views
php artisan dg:blade-tailwind:extract ./resources/views/components
```

**2. Single file path:**

```
php artisan dg:blade-tailwind:extract resources/views/livewire/garage/list/item.blade.php
php artisan dg:blade-tailwind:extract components/card.blade.php
```

**3. Pattern matching (searches in configured search\_path):**

```
php artisan dg:blade-tailwind:extract *preview*
php artisan dg:blade-tailwind:extract *card*.blade.php
php artisan dg:blade-tailwind:extract list-item
```

**4. Multiple targets (comma-separated, can mix patterns and files):**

```
php artisan dg:blade-tailwind:extract image-preview.blade.php,card-list.blade.php
php artisan dg:blade-tailwind:extract *preview*,*card*,header.blade.php
```

### Restore Classes (Production → Development)

[](#restore-classes-production--development)

Restore Tailwind classes for editing (accepts same target formats as extract):

```
# No target (with confirmation prompts)
php artisan dg:blade-tailwind:restore

# Directory
php artisan dg:blade-tailwind:restore ./resources/views

# Pattern
php artisan dg:blade-tailwind:restore *preview*

# Specific file
php artisan dg:blade-tailwind:restore components/card.blade.php

# Multiple
php artisan dg:blade-tailwind:restore *card*,*list*
```

**Automatic CSS Cleanup:** When you restore classes, the command automatically removes the restored CSS rules from the output file, keeping your CSS clean and preventing stale rules from accumulating.

### Workflow

[](#workflow)

**Option A: Automated (New Files)**

1. **Wrap** your Blade file to identify and mark repeated class lists
2. **Extract** marked classes to generate compact CSS
3. **Commit** both Blade files and CSS file

**Option B: Manual (Existing Workflow)**

1. Manually add `__name__ classes __` markers around classes you want to extract
2. **Extract** to generate compact CSS
3. **Commit** both Blade files and CSS file

**Option C: Editing Existing Extracted Files**

1. **Restore** before editing (restore Tailwind classes to inline format)
2. **Edit** your Blade files normally
3. **Extract** after editing (compact back to short class names)
4. **Commit** both Blade files and CSS file

You can add markers manually or use the `wrap` command to add them automatically.

**Manual approach:**Wrap classes you want to extract with double underscores:

```

```

**Automated approach:**Use the wrap command to automatically identify and mark class lists:

```
php artisan dg:blade-tailwind:wrap your.view.namelass="__card-wrapper__ flex flex-col gap-2 p-4 __">

```

After extraction:

```

```

**Important:** The `group` and `peer` Tailwind classes **cannot** be extracted (they break parent-child selectors). The tool will warn and skip them automatically.

Configuration
-------------

[](#configuration)

Configuration file: `config/dg-blade-tailwind-extract.php`

```
return [
    // CSS output file path
    'css_output_path' => resource_path('css/tw-extracted.css'),

    // Class prefix (default: TW)
    'class_prefix' => 'TW',

    // Hash length for file-based collision avoidance (default: 4)
    'hash_length' => 4,

    // Default search path when using pattern matching
    'search_path' => resource_path('views'),

    // Directories to ignore during file scanning
    'ignored_directories' => [
        './vendor/',
        'vendor/',
        './node_modules/',
        'node_modules/',
    ],

    // Reserved Tailwind classes that cannot be extracted
    // These use parent-child selectors that break when extracted to @apply
    // Also checks for variants like 'group/' and 'peer/'
    'reserved_classes' => [
        'group',
        'peer',
    ],

    // Safety limit for extraction loops
    'max_iterations' => 10,
];
```

**Note:** When the extract command encounters patterns containing reserved classes (like `group`, `group/item`, or `peer`), it will:

- Skip extraction for that pattern
- Display an informative warning showing which patterns were skipped and why
- Continue processing other patterns in the same file

Advanced Usage
--------------

[](#advanced-usage)

### Custom CSS Output Path

[](#custom-css-output-path)

```
php artisan dg:blade-tailwind:extract ./resources/views --css-file=resources/css/my-custom.css
```

### Working with Livewire Components

[](#working-with-livewire-components)

The tool works seamlessly with Livewire's `->class([...])` method and Blade's `@class([...])` directive:

**Before Extraction:**

```
 $selected,
])>
```

**After Extraction:**

```
 $selected,
])>
```

Wrap Mode (Optional Preparation):\*\*

- Scans for class lists with minimum number of classes (default: 3)
- Automatically deduplicates identical class lists
- Generates semantic wrapper names: `__adjective-noun-number__`
- Marks class lists: `__name__ classes __`
- Skips protected patterns (material-symbols-outlined, TW-, etc.)
- Shows summary with occurrence counts

2. **Extract Mode:**

    - Scans for `__name__ tailwind classes __` patterns
    - Generates short class names: `{PREFIX}-{HASH}-{NAME}`
    - Writes `@apply` rules to the CSS file
    - Replaces inline classes with short names
3. **Restore Mode:**

    - Reads existing `@apply` rules from CSS file
    - Finds short class names in Blade files
    - Restores original Tailwind class strings
4. **Extract Mode:**

    - Scans for `__name__ tailwind classes __` patterns
    - Generates short class names: `{PREFIX}-{HASH}-{NAME}`
    - Writes `@apply` rules to the CSS file
    - Replaces inline classes with short names
5. **Restore Mode:**

    - Reads existing `@apply` rules from CSS file
    - Finds short class names in Blade files
    - Restores original Tailwind class strings
6. **File Hash:**

    - Each file gets a unique 4-character hash (configurable)
    - Prevents class name collisions between files
    - Allows same semantic name (`card-wrapper`) across different files

Gotchas &amp; Best Practices
----------------------------

[](#gotchas--best-practices)

- ⚠️ Never manually edit `TW-*` class names in extracted files
- ⚠️ Always restore → edit → extract workflow
- ⚠️ Don't extract `group`, `peer`, or other parent-modifier classes
- ✅ Commit both Blade and CSS files together
- ✅ Run extract before deploying to production
- ✅ Run restore before starting development

Testing
-------

[](#testing)

```
composer test
```

Security
--------

[](#security)

If you discover any security-related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [dxgx](https://github.com/dxgx)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

Changelog
---------

[](#changelog)

Please see [CHANGELOG.md](CHANGELOG.md) for recent changes.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance98

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

17

Last Release

9d ago

Major Versions

v1.1.5 → v2.0.02026-05-21

### Community

Maintainers

![](https://www.gravatar.com/avatar/f2a12a26ca730b7645484bc8744660dcde380c213b39e6b626e1be872444f4ae?d=identicon)[dxgx](/maintainers/dxgx)

---

Top Contributors

[![dxgx](https://avatars.githubusercontent.com/u/3294038?v=4)](https://github.com/dxgx "dxgx (25 commits)")

---

Tags

laravelperformancebladelivewiretailwindcssdxgx

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/dxgx-blade-tailwind-extract/health.svg)

```
[![Health](https://phpackages.com/badges/dxgx-blade-tailwind-extract/health.svg)](https://phpackages.com/packages/dxgx-blade-tailwind-extract)
```

###  Alternatives

[spatie/laravel-responsecache

Speed up a Laravel application by caching the entire response

2.8k8.7M64](/packages/spatie-laravel-responsecache)[tightenco/jigsaw

Simple static sites with Laravel's Blade.

2.2k449.3k30](/packages/tightenco-jigsaw)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9732.3M121](/packages/roots-acorn)[laravel/ai

The official AI SDK for Laravel.

9782.1M153](/packages/laravel-ai)[robsontenorio/mary

Gorgeous UI components for Livewire powered by daisyUI and Tailwind

1.5k531.0k21](/packages/robsontenorio-mary)[tallstackui/tallstackui

TallStackUI is a powerful suite of Blade components that elevate your workflow of Livewire applications.

719160.4k12](/packages/tallstackui-tallstackui)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
