Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tall Laravel Package

bebo925/tall

TALL Stack preset for Laravel with Blade components for buttons, inputs, panels, tables, modals, messages, and page headings. Install via Composer and run tall:install to scaffold JS deps, Tailwind, Mix, and app layout.

View on GitHub
Deep Wiki
Context7

Getting Started

The package is a TALL-stack (Tailwind + Alpine + Livewire) preset plus a set of Blade UI components. You get the scaffolding and pre-styled components in one install.

1. Install

composer require bebo925/tall
php artisan tall:install

tall:install is the workhorse: it installs JS dependencies, writes a tailwind.config.js, touches your build tooling config, and publishes an app.blade.php layout. Back up tailwind.config.js, vite.config.js, and webpack.mix.js before running it — the installer overwrites rather than merges.

2. Fix HMR

Edit the host variable in vite.config.js so hot reloading resolves correctly (especially important if you develop in Docker, Sail, or a VM):

// vite.config.js
server: {
    host: 'localhost', // or your container host
},

3. Publish views if you intend to customize

php artisan vendor:publish --tag="tall-views"

Do this on day one if you expect to touch markup. Editing components after you've already built ten screens against the default markup is more churn than publishing up front.

First use case to try: a CRUD form. Wrap your Livewire form fields in <x-tall::input> and drop in <x-tall::messages /> at the top of the layout — this immediately exercises the input wrapper, error binding, and flash messaging in one screen:

<form wire:submit="save">
    <x-tall::input label="Name" error="name">
        <x-tall::input.text wire:model="name" />
    </x-tall::input>

    <x-tall::button style="primary" type="submit">Save</x-tall::button>
</form>

Where to look first: the published resources/views/vendor/tall/ directory after vendor:publish. The README documents the call sites well but not the component internals — reading the published Blade files is the fastest way to understand what props and slots actually exist.

Implementation Patterns

Form composition: wrapper + field

The core pattern is a label/error wrapper (x-tall::input) around a field component (x-tall::input.text, .checkbox, .radio, .textarea, .select, .rich-text). The wrapper owns layout, label text, and error display; the field owns the control.

<x-tall::input label="Role">
    <x-tall::input.select wire:model="role">
        <option value="admin">Admin</option>
        <option value="member">Member</option>
    </x-tall::input.select>
</x-tall::input>

The error="property_name" prop on the wrapper is what ties the control to a Livewire validation error bag. This is the single most important prop to get right — a typo here means validation messages silently never render (see Gotchas).

Flash messaging via session

components/layouts/app.blade.php ships with <x-tall::messages /> already included. Push notifications from any controller or Livewire action:

session()->flash('message', [
    'type' => 'success',   // also: warning, danger
    'message' => 'Saved successfully!',
]);

For non-redirect flows (e.g. inside a Livewire action that stays on the page), use Livewire's browser event instead — the messages component listens for it:

$this->dispatch('notify', type: 'success', message: 'Saved!');

<x-tall::messages dark="true" /> is available if you run a dark layout.

Modal confirmation dialogs

The package bundles wire-elements/modal and ships a tall-confirmation-dialog component. The idiomatic pattern is dispatching openModal with a confirmation payload:

$this->dispatch('openModal', [
    'component' => 'tall-confirmation-dialog',
    'arguments' => [
        'message'     => 'Delete this record? This cannot be undone.',
        'title'       => 'Warning',
        'data'        => $recordId,
        'confirmText' => 'Delete',
        'style'       => 'danger',
        'event'       => 'recordDeleted',  // event fired on confirm
    ],
]);

Then listen for the confirm event in your Livewire component:

#[On('recordDeleted')]
public function destroy($id) { /* ... */ }

This is the highest-leverage pattern in the package — it eliminates hand-rolling per-model confirmation dialogs and keeps the danger styling consistent.

Tables

Compose tables from table, table.heading, table.row, table.cell. Use it for admin listings where you want the visual consistency without building a DataTable abstraction:

<x-tall::table>
    <x-slot name="head">
        <x-tall::table.heading>Name</x-tall::table.heading>
        <x-tall::table.heading>Email</x-tall::table.heading>
    </x-slot>
    <x-slot name="body">
        @foreach ($users as $user)
            <x-tall::table.row>
                <x-tall::table.cell>{{ $user->name }}</x-tall::table.cell>
                <x-tall::table.cell>{{ $user->email }}</x-tall::table.cell>
            </x-tall::table.row>
        @endforeach
    </x-slot>
</x-tall::table>

Rich text and markdown

<livewire:tall-markdown-x> is a Livewire component, not a Blade one — bind via :content and pass Tailwind classes per-region via a style array:

<livewire:tall-markdown-x :content="$post->body ?? ''" :style="[
    'toolbar'  => 'flex items-center justify-between border-b',
    'textarea' => 'h-[60vh] p-4 w-full focus:outline-none',
    'preview'  => 'p-10 prose max-w-none',
    'help'     => 'p-8 prose max-w-none',
]" />

The style-array pattern is your main theming lever for this component — it avoids forking the view.

Multi-select

<x-tall::multiple-select
    :options="Team::all()"
    wire:model.defer="selectedTeamIds"
/>

Defaults to id / name for value/label fields. If your model's display column differs, pass valueField / labelField explicitly rather than renaming columns.

Dropdowns

<x-tall::dropdown>
    <x-slot name="trigger">
        <x-tall::button style="secondary">Actions</x-tall::button>
    </x-slot>
    <x-tall::dropdown.item wire:click="edit">Edit</x-tall::dropdown.item>
    <x-tall::dropdown.item wire:click="archive">Archive</x-tall::dropdown.item>
</x-tall::dropdown>

Because the dropdown relies on Alpine, wire:click inside items works but wire:model inside a dropdown item does not — keep dropdown contents action-only.

Layout structure

Build pages from x-tall::page-heading (with meta and actions slots) followed by one or more x-tall::panel blocks (body and footer slots). This establishes a consistent rhythm across an admin app with almost no CSS authoring:

<x-tall::page-heading title="Users">
    <x-slot name="actions">
        <x-tall::button style="primary" wire:click="create">New User</x-tall::button>
    </x-slot>
</x-tall::page-heading>

<x-tall::panel title="All Users">
    <x-slot name="body">{{-- table --}}</x-slot>
</x-tall::panel>

Gotchas and Tips

The installer is opinionated and destructive. tall:install writes tailwind.config.js and touches build configs. If you already have a Tailwind theme, commit first and diff the results. In particular, custom colors, fonts, and darkMode settings will be lost unless you merge them back.

Vite vs. Webpack Mix is contradictory in the docs. The README says the installer updates webpack.mix.js and tells you to edit vite.config.js for HMR. The package's actual supported path appears to be Vite. If you're on Laravel Mix (Laravel ≤9-era projects), treat this as a full Vite migration task, not a drop-in. Don't assume both toolchains are supported simultaneously.

The README has literal typos you must correct at the call site. The install command line contains //includes https://github.com/wire-elements/modal as an inline comment — do not paste it verbatim into your shell. The panel example closes with </x-tall::panel.body> which does not exist; the correct closing tag is </x-tall::panel>. These aren't stylistic — copying the README blindly produces parse errors and "component not found" exceptions.

error="property_name" must match the Livewire property exactly. This is the #1 source of "my validation messages don't show" bugs. The wrapper doesn't introspect the bound property; it's a manual string match. If you refactor a property name, grep for its error="..." usage.

Validation display depends on Livewire's error bag being scoped to that component. If the form is nested inside a child Livewire component but the wrapper lives in a parent — or the error prop points to a property on a different component — nothing renders. Keep the wrapper and the invalid property in the same component.

Modal components require Livewire. wire-elements/modal is a hard dependency. In an Alpine-only page, $dispatch('openModal', ...) fires into the void. If you're mixing Livewire and non-Livewire pages, gate modal dispatch behind Livewire components and confirm the modal container is mounted in your layout (the package's app.blade.php handles this; a custom layout may not).

rich-text and multiple-select are Livewire components, not Blade components. They're invoked with livewire: prefixes. Mixing the syntaxes (<x-tall::rich-text> vs <livewire:tall-markdown-x>) produces confusing "unable to locate component" errors. Check the README example for each one rather than assuming.

Check Alpine/Livewire load order after install. The installer creates app.blade.php with specific script ordering. If you've merged it into an existing layout and reordered @livewireScripts, @stack('scripts'), or the Alpine CDN/Vite import, dropdowns and modals will break with no console error beyond an Alpine initialization warning. When debugging an unresponsive dropdown, inspect whether Alpine loaded after Livewire.

Publishing views is the primary extension point. There is no documented plugin API, no design-token layer, and no runtime theming. To add a new button style, you publish the views, edit components/button.blade.php, and add a variant to the internal match/switch. Accept this: customization means forking markup, and you own the merge burden on package updates.

Tailwind purging may drop component styles. Components use string-concatenated class names in some spots; if you're on an older Tailwind with a naive purge/content config, classes emitted only from the package's compiled views won't be detected. Ensure content includes the vendor view path (or your published copy) in tailwind.config.js.

Single-maintainer, one-star project — pin the version. With zero dependents and one maintainer, treat upgrades as manual review tasks. Pin an exact version in composer.json, publish the views so you're not coupled to upstream markup, and re-read the released diff before composer update. The upside is a small surface area: the components are mostly presentational Blade, so forking is cheap if the package goes stale.

Debugging checklist when a component renders blank: (1) did you vendor:publish --tag="tall-views" or is the vendor path registered; (2) is the component name spelled with the tall:: namespace; (3) does the slot name match exactly (body, footer, head, meta, actions, trigger) — unnamed content goes to the default slot and will be silently ignored by components expecting named slots.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator