PHPackages                             redbastie/tailwire - 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. [Framework](/categories/framework)
4. /
5. redbastie/tailwire

AbandonedArchivedLibrary[Framework](/categories/framework)

redbastie/tailwire
==================

Build reactive web apps without having to write HTML, CSS, or JavaScript! Powered by Laravel Livewire and Tailwind.

2.1.17(5y ago)551656[3 issues](https://github.com/redbastie/tailwire/issues)MITPHPPHP ^8.0

Since Jan 26Pushed 4y ago5 watchersCompare

[ Source](https://github.com/redbastie/tailwire)[ Packagist](https://packagist.org/packages/redbastie/tailwire)[ Docs](https://github.com/redbastie/tailwire)[ RSS](/packages/redbastie-tailwire/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (7)Versions (40)Used By (0)

No Longer Maintained
====================

[](#no-longer-maintained)

Please check out my new package here:

It's a much better implementation of what this package was trying to do.

Tailwire
========

[](#tailwire)

Build reactive web apps without having to write HTML, CSS, or JavaScript! Powered by Laravel Livewire and Tailwind.

Imagine a world where you no longer have to constantly context switch between HTML, CSS, and Javascript. Where all of your code can reside in self-contained PHP component classes. Even your database migration logic can stay inside of your models. It's kind of like SwiftUI for PHP!

[![](https://camo.githubusercontent.com/1cfa9cda42535103eb2e18303d1c1f8b0b9fcc8d9c94ba57a1c0b2ef31e4c9d1/68747470733a2f2f692e696d6775722e636f6d2f6a4536765937302e706e67)](https://www.youtube.com/watch?v=UhC_jBIXYWE)

#### Requirements

[](#requirements)

- Laravel 8
- PHP 8
- NPM

#### Features

[](#features)

- Expressive HTML builder written using PHP
- Tailwind styling &amp; configuration built in
- Laravel Livewire component property &amp; action wiring
- Handy directives for if, each, include, etc. statements
- Commands for install, auth, components, CRUD, models, &amp; automatic migrations
- Automatic component routing
- Automatic model migrations
- Automatic user timezones
- Easy app versioning
- PWA capabilities (standalone launcher, icons, etc.)
- Swipe down refresh (iOS PWA)
- Infinite scrolling
- Heroicon integration
- Honeypot spam rejection
- &amp; more!

#### Packages Used

[](#packages-used)

- [Laravel Livewire](https://github.com/livewire/livewire)
- [Laravel Timezone](https://github.com/jamesmills/laravel-timezone)
- [Doctrine DBAL](https://github.com/doctrine/dbal)
- [Honey](https://github.com/lukeraymonddowning/honey)
- [TailwindCSS](https://github.com/tailwindlabs/tailwindcss)
- [Blade Heroicons](https://github.com/blade-ui-kit/blade-heroicons)

#### Docs

[](#docs)

- [Installation](#installation)
- [Commands](#commands)
    - [Install Tailwire](#install-tailwire)
    - [Generate auth scaffolding](#generate-auth-scaffolding)
    - [Generate a component](#generate-a-component)
    - [Generate CRUD components](#generate-crud-components)
    - [Generate a Tailwire model](#generate-a-tailwire-model)
    - [Run automatic migrations](#run-automatic-migrations)
- [Usage](#usage)
    - [Routing full page components](#routing-full-page-components)
    - [Extending layout components](#extending-layout-components)
    - [Building HTML elements](#building-html-elements)
    - [Styling elements via Tailwind](#styling-elements-via-tailwind)
    - [Wiring elements via Livewire](#wiring-elements-via-livewire)
    - [Using directives &amp; other methods](#using-directives--other-methods)
- [Extras](#extras)
    - [Swipe down refresh](#swipe-down-refresh)
    - [Infinite scrolling](#infinite-scrolling)

#### Links

[](#links)

- Support: [GitHub Issues](https://github.com/redbastie/swift/issues)
- Contribute: [GitHub Pulls](https://github.com/redbastie/swift/pulls)
- Donate: [PayPal](https://www.paypal.com/paypalme2/kjjdion)

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

[](#installation)

Create a new Laravel 8 project:

```
laravel new my-app
```

Configure your `.env` app, database, and mail values:

```
APP_*
DB_*
MAIL_*
```

Require Tailwire via composer:

```
composer require redbastie/tailwire
```

Install Tailwire:

```
php artisan tailwire:install
```

Commands
--------

[](#commands)

### Install Tailwire

[](#install-tailwire)

```
php artisan tailwire:install
```

Installs the layout &amp; index components, User model &amp; factory, config files, icons, PWA manifest, Tailwind CSS &amp; config, JavaScript assets, webpack, and runs the necessary NPM commands.

### Generate auth scaffolding

[](#generate-auth-scaffolding)

```
php artisan tailwire:auth
```

Generates auth components including login, logout, register, password reset, and home.

### Generate a component

[](#generate-a-component)

```
php artisan tailwire:component {class} {--full} {--modal} {--list} {--model=}
```

Generates a Tailwire component. Use `--full` to generate a full page component, `--modal` for a modal, `--list --model=ModelClass` for a list, or omit all options for a basic component.

#### Examples

[](#examples)

```
php artisan tailwire:component VehicleItem
php artisan tailwire:component VehiclePage --full
php artisan tailwire:component Admin/InsuranceDialog --modal
php artisan tailwire:component VehicleList --list --model=Vehicle
```

### Generate CRUD components

[](#generate-crud-components)

```
php artisan tailwire:crud {class}
```

Generates CRUD components for the specified model class. If the model class does not exist, it will be created along with a factory automatically.

If you specify `User` as the class, full user CRUD will be generated.

#### Examples

[](#examples-1)

```
php artisan tailwire:crud Vehicle
php artisan tailwire:crud Admin/Insurance
```

### Generate a Tailwire model

[](#generate-a-tailwire-model)

```
php artisan tailwire:model {class}
```

Generates a Tailwire model and factory which comes with the automatic migration method and factory definition included. As with other commands, you can specify a subdirectory for the class.

#### Examples

[](#examples-2)

```
php artisan tailwire:model Vehicle
php artisan tailwire:model Admin/Insurance
```

### Run automatic migrations

[](#run-automatic-migrations)

```
php artisan tailwire:migrate {--fresh} {--seed} {--force}
```

Runs automatic migrations for all of your Tailwire models which have a `migration` method specified. This uses Doctrine to automatically diff your database and apply the necessary changes.

Optionally use `--fresh` to wipe the database, and `--seed` to run your seeders afterwards. If you wish to run this in production, use the `--force`.

Note that if you still want to use traditional Laravel migration files, they will run *before* automatic migration methods.

Usage
-----

[](#usage)

### Routing full page components

[](#routing-full-page-components)

```
class Login extends Component
{
    public $routeUri = '/login';
    public $routeName = 'login';
    public $routeMiddleware = 'guest';
```

Specify public `$route*` properties in your Tailwire component in order to enable automatic routing. A minimum of `$routeUri` is required in order to enable automatic routing for the component. Available properties include `$routeUri`, `$routeName`, `$routeMiddleware` (string or array), `$routeDomain`, `$routeWhere` (array).

If using route parameters, be sure to include them in a `mount` method:

```
class Vehicle extends Component
{
    public $routeUri = '/vehicle/{vehicle}';
    public $routeName = 'vehicle';
    public $routeMiddleware = ['auth'];
    public $vehicle;

    public function mount(Vehicle $vehicle)
    {
        $this->vehicle = $vehicle;
    }
```

### Extending layout components

[](#extending-layout-components)

```
class Login extends Component
{
    public $viewTitle = 'Login';
    public $viewExtends = 'layouts.app';
```

Specify a `$viewExtends` property which uses dot notation to point to the component that this component will extend. In this example, the `$viewExtends` property is pointing to the `Layouts/App` component.

In the `Layouts/App` component, the `$v->yield()` method is used in order to render the child component inside:

```
class App extends Component
{
    public function view(View $v)
    {
        return $v->body(
            $v->header('Header content')->class('text-xl'),
            $v->yield(),
            $v->footer('Footer content')->class('text-sm'),
        )->class('bg-gray-100');
```

### Building HTML elements

[](#building-html-elements)

```
class Home extends Component
{
    public function view(View $v)
    {
        return $v->section(
            $v->h1('Home')->class('text-xl px-6 py-4'),
            $v->p('You are logged in!')->class('p-6')
        )->class('bg-white shadow divide-y');
    }
```

Tailwire uses an expressive syntax in order to build HTML elements. As you can see, the `$v` variable is used to construct each element in the view. The first method of a `$v` chain consists of the HTML element name. A list of available HTML element names can be found here: [HTML Element Reference](https://www.w3schools.com/tags/default.asp)

After the first method, each additional chained method represents an attribute of the element. For example, creating an image:

```
$v->img()->src(asset('images/icon-fav.png'))->class('w-5 h-5')
```

This would translate to an image with an `src` of the asset URL, using the Tailwind classes `w-5 h-5` for styling. A list of available HTML element attributes can be found here: [HTML Attribute Reference](https://www.w3schools.com/tags/ref_attributes.asp)

In this example, you can see that the `img` method does not accept any parameters, because it does not use a closure tag. Elements that use a closure tag, such as `div`, do accept `...$content` parameters, which you can use in order to build content inside:

```
$v->div(
    $v->p('Hello')->class('text-red-600'),
    $v->p('World')->class('text-green-600'),
)->class('bg-blue-100')
```

### Styling elements via Tailwind

[](#styling-elements-via-tailwind)

```
$v->icon('refresh')->class('animate-spin text-gray-400 w-5 h-5 mx-auto')
```

Specify the Tailwind classes for an element within the chained `class()` method.

Now you might be thinking, "but there isn't autocomplete!" Good news; install the VSCode extension "Tailwind CSS Intellisense", then add the following to your `settings.json`:

```
"tailwindCSS.experimental.classRegex": [
    "class\\([\"']([^\"']*)[\"']\\)"
],
```

### Wiring elements via Livewire

[](#wiring-elements-via-livewire)

Along with HTML attributes, Tailwire also allows you to wire up your elements to make them reactive via Livewire. The method names are specified according to Livewire attribute conventions, which can be found here: [Laravel Livewire docs](https://laravel-livewire.com/docs/2.x/quickstart)

#### Modelling data

[](#modelling-data)

```
$v->input()->type('email')->id('email')->wireModelDefer('email')
```

Tailwire components contain a public `$model` array which will contain the data that is modelled through elements like inputs, selects, etc.

You can grab the data using the `$this->model()` helper method:

```
$email = $this->model('email');
```

If your modelled data is an array, you can use the dot notation to grab values from the array:

```
$userName = $this->model('user.name');
```

You validate the `$model` data using `$this->validate()`:

```
$validated = $this->validate([
    'email' => ['required', 'email'],
]);
```

When checking for validation errors, you can use the `$this->error()` method to check if a validation error exists for the modelled data:

```
$v->if($this->error('email'),
    fn() => $v->p($this->error('email'))->class('text-xs text-red-600')
)
```

#### Performing actions

[](#performing-actions)

```
class Counter extends Component
{
    public $count = 0;

    public function view(View $v)
    {
        return $v->div(
            $v->button('Increment Count')->wireClick('incrementCount'),
            $v->p($this->count)->class('text-blue-600'),
        );
    }

    function incrementCount()
    {
        $this->count++;
    }
```

As you can see, you can wire up particular actions via the `wire*` methods as well. This includes things like clicking, polling, submitting, etc. If your action uses parameters, simply specify them in the `wire*` method:

```
public function view(View $v)
{
    return $v->div(
        $v->button('Increment Count')->wireClick('incrementCount', 2),
        $v->p($this->count)->class('text-blue-600'),
    );
}

function incrementCount($amount)
{
    $this->count += $amount;
}
```

The beauty of this is that it allows you to keep all of your logic inside the Tailwire component classes themselves! No more switching between tons of files and languages and wondering where things happen.

### Using directives &amp; other methods

[](#using-directives--other-methods)

The `View $v` variable also allows you to use some handy directives inside your `view` method, such as if statements, each loops, includes, and more.

#### If statements

[](#if-statements)

```
$v->if(Auth::guest(),
    fn() => $v->p('You are signed out.')
)->else(
    fn() => $v->p('You are signed in!)
)
```

#### Each loops

[](#each-loops)

```
$v->each(Vehicle::all(),
    fn(Vehicle $vehicle) => $v->div(
        $v->p($vehicle->name),
        $v->p($vehicle->created_at)->class('text-xs text-gray-600')
    )
)->empty(
    fn() => $v->p('No vehicles found.')
),
```

#### Including partial components

[](#including-partial-components)

```
$v->include('user-list-item', $user),
```

#### Heroicons ([list of available icons here](https://heroicons.com))

[](#heroicons-list-of-available-icons-here)

```
$v->icon('cog')->class('text-blue-600 w-5 h-5'),
```

#### Swipe down to refresh indicator (for iOS PWA's)

[](#swipe-down-to-refresh-indicator-for-ios-pwas)

```
$v->swipeDownRefresh(
    $v->icon('refresh')->class('animate-spin text-gray-400 w-5 h-5 mx-auto')
)->class('mb-4'),
```

#### Infinite scrolling indicator

[](#infinite-scrolling-indicator)

```
$v->infiniteScroll(
    $v->icon('refresh')->class('animate-spin text-gray-400 w-5 h-5 mx-auto')
)->class('mt-4'),
```

Extras
------

[](#extras)

### Swipe down refresh

[](#swipe-down-refresh)

```
$v->swipeDownRefresh(
    $v->icon('refresh')->class('animate-spin text-gray-400 w-5 h-5 mx-auto')
)->class('mb-4'),
```

If a user has scrolled `-100px` from the top of the page, the `swipeDownRefresh` element will display briefly before the entire page is reloaded. This is useful for PWA's, when the user adds your web app to their home screen and needs a way to refresh the page.

### Infinite scrolling

[](#infinite-scrolling)

```
public function view(View $v)
{
    return $v->section(
        $v->h1('Vehicles')->class('text-xl mb-2'),

        $v->each($this->query()->paginate($this->perPage),
            fn(Vehicle $vehicle) => $v->div(
                $v->p($vehicle->name),
                $v->p(timezone($vehicle->created_at))->class('text-xs text-gray-600')
            )->class('px-6 py-4')
        ),

        $v->if($this->query()->count() > $this->perPage,
            fn() => $v->infiniteScroll(
                $v->icon('refresh')->class('animate-spin text-gray-400 w-5 h-5 mx-auto')
            )->class('mt-4')
        )
    );
}

public function query()
{
    return Vehicle::query()->orderBy('name');
}
```

Each Tailwire component contains a `$perPage` public property which is incremented if the hidden `infiniteScroll` element is present on the page and the user scrolls `100px` from the bottom. After it is incremented, the component should load more items and hide the `infiniteScroll` element again. See how `query()`, `paginate()`, `count()`, and `$perPage` are used in the example above.

### Honeypot spam prevention

[](#honeypot-spam-prevention)

```
$v->form(
    $v->div(
        $v->label('Email')->for('email'),
        $v->input()->type('email')->id('email')->wireModelDefer('email')
            ->class(($this->error('email') ? 'border-red-500' : 'border-gray-300') . ' w-full'),
        $v->if($this->error('email'), fn() => $v->p($this->error('email'))->class('text-xs text-red-600'))
    )->class('space-y-1'),

    $v->div(
        $v->label('Password')->for('password'),
        $v->input()->type('password')->id('password')->wireModelDefer('password')
            ->class(($this->error('password') ? 'border-red-500' : 'border-gray-300') . ' w-full'),
        $v->if($this->error('password'), fn() => $v->p($this->error('password'))->class('text-xs text-red-600'))
    )->class('space-y-1'),

    $v->honey(), // stop spam bots!

    $v->button('Register')->type('submit')->class('text-white bg-blue-600 w-full py-2')
)->wireSubmitPrevent('register')->class('space-y-4 p-6')
```

Tailwire uses [Honey](https://github.com/lukeraymonddowning/honey) for spam bot prevention. See the repo for that package for more information. You can also use recaptcha by passing `true` to the element:

```
$v->honey(true) // use honey with recaptcha (be sure to configure it!)
```

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance19

Infrequent updates — may be unmaintained

Popularity24

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity70

Established project with proven stability

 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

39

Last Release

1909d ago

Major Versions

1.0.3 → 2.0.02021-02-03

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/64050101?v=4)[redbastie](/maintainers/redbastie)[@redbastie](https://github.com/redbastie)

---

Top Contributors

[![redbastie](https://avatars.githubusercontent.com/u/64050101?v=4)](https://github.com/redbastie "redbastie (52 commits)")

### Embed Badge

![Health badge](/badges/redbastie-tailwire/health.svg)

```
[![Health](https://phpackages.com/badges/redbastie-tailwire/health.svg)](https://phpackages.com/packages/redbastie-tailwire)
```

###  Alternatives

[mhmiton/laravel-modules-livewire

Using Laravel Livewire in Laravel Modules package with automatically registered livewire components for every modules.

236409.6k9](/packages/mhmiton-laravel-modules-livewire)[raugadh/fila-starter

Laravel Filament Starter.

614.9k](/packages/raugadh-fila-starter)

PHPackages © 2026

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