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

Wireui Laravel Package

ph7jack/wireui

WireUI is a Laravel Livewire component library built on Tailwind CSS, offering ready-made forms, modals, notifications, dialogs, and other customizable UI elements to speed up building modern, accessible web interfaces.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the matching major. composer require ph7jack/wireui — pair the major version with your Livewire major (WireUI 2.x ⇄ Livewire 3, WireUI 1.x ⇄ Livewire 2). Check the constraint before you run it, not after a broken wire:model.
  2. Run the installer. php artisan wireui:install publishes config/wireui.php, adds the WireUI preset to tailwind.config.js, and registers component aliases (x-button, x-input, x-modal, …).
  3. Verify Tailwind actually sees the vendor views. Your content array must include ./vendor/ph7jack/wireui/resources/**/*.blade.php and ./vendor/ph7jack/wireui/src/View/**/*.php. The installer usually appends these; re-check if you use a custom preset or Tailwind v4's CSS-first config.
  4. Wire the layout. Add @wireuiScripts before </body> (after @vite/@livewireScripts), plus <x-notifications /> — and <x-dialog /> on versions where the confirm dialog needs a mount point.
  5. First use case: take an existing hand-rolled form partial and swap in <x-input>, <x-select>, and <x-button>, then fire a success toast from the Livewire action. That two-hour change is the honest measure of whether the package earns its place.

Where to look first: config/wireui.php (defaults, aliases, notification position), vendor/ph7jack/wireui/resources/views/components/ (the actual markup you'll be overriding), then the docs site.

use WireUi\Traits\WireUiActions;

class CreateUser extends Component
{
    use WireUiActions;

    public string $name = '';

    public function save(): void
    {
        $this->validate(['name' => 'required|min:3']);
        User::create(['name' => $this->name]);

        $this->notification()->success(
            title: 'Saved',
            description: 'The user was created.'
        );
    }
}

Implementation Patterns

Forms. Bind wire:model straight onto WireUI inputs; they forward unknown attributes to the inner <input>. Reach for x-select with option-key/option-value instead of hand-rolling an Eloquent loop, x-errors for validation bags, and x-toggle/x-datetime-picker/x-currency where you'd otherwise be pasting a JS library.

<x-input wire:model="name" label="Name" hint="At least 3 characters" />
<x-errors name="name" />

<x-select
    wire:model="role"
    label="Role"
    :options="$roles"
    option-value="id"
    option-key="name"
/>

Modals as Livewire state. Let a boolean property own visibility and let the component emit close; don't manage modals with ad-hoc JS classes. This keeps the create/edit flow testable and survives re-renders.

<x-modal-card wire:model="showForm" title="New user">
    <x-input wire:model="name" label="Name" />
    <x-slot name="footer">
        <x-button flat label="Cancel" x-on:click="close" />
        <x-button primary label="Save" wire:click="save" spinner="save" />
    </x-slot>
</x-modal-card>

Notifications replace session()->flash. One-liner success/error/info/warning calls from any Livewire action, with the toast rendering handled globally instead of per-view. This is the highest-leverage feature in the package — it deletes flash-partial boilerplate from every controller and layout.

Confirm before destructive work without writing JS.

$this->dialog()->confirm([
    'title' => 'Delete user?',
    'description' => 'This cannot be undone.',
    'accept' => ['label' => 'Delete', 'method' => 'destroy', 'params' => $userId],
]);

Wrap, don't sprinkle. Build one local <x-form.input> around x-input that standardises label/hint/error layout, and use it everywhere. When you later need to change how errors render, you change one file rather than 200 call sites — and you keep a seam for swapping WireUI out.

Theme once in config. Set brand colours and default variants in config/wireui.php (style.color, etc.) rather than passing color="primary" at every call site; use the class passthrough only for genuine one-offs.

Testing. Livewire::test() still exercises the PHP side fully. Assert the business effect (record deleted, user created) and, if you want the UI contract covered, assert the specific Livewire events the trait dispatches — read the trait source for exact event names rather than guessing.

Gotchas and Tips

  • Unstyled components are almost always Tailwind content paths, not a broken install. Second most common cause: Tailwind v4 ignoring tailwind.config.js, where the shipped preset never gets applied.
  • Double-loaded Alpine silently kills interactivity (dropdowns, modals, masks). Don't import Alpine and Alpine.start() yourself if @wireuiScripts already handles it.
  • Notifications/dialogs with no mount point fail silently: the PHP call succeeds, nothing renders, no error. If "notifications don't work," check the layout for <x-notifications /> / <x-dialog /> before debugging the component.
  • Config changes need a cache clear. config/wireui.php drives component alias registration at boot; run php artisan config:clear (and remember CI's config:cache) after editing aliases.
  • Alias collisions. If your app already has an <x-button>, use the namespaced form (<x-wireui::button>) or rename via the alias config rather than deleting your own component.
  • x-select with an Eloquent collection without option-value/option-key yields "Array to string conversion" — set them explicitly.
  • Icon names fail quietly. x-icon renders empty for a nonexistent name; confirm the configured icon style (heroicons vs. fontawesome) matches the names you're using.
  • Stray modal backdrops after wire:navigate. If navigation leaves overflow-hidden on <body> or an orphaned overlay, clean up on the livewire:navigated event.
  • Overriding views is a commitment. Publishing component views to restyle them means you own the diff across upgrades. Prefer config + wrapper components; publish only for markup you genuinely can't reach otherwise.
  • Package identity. The project has shipped under more than one Composer name over its life — don't end up with two copies in composer.json, and read the changelog before crossing a major (props have been renamed between majors).
  • Small ecosystem. ~1.8k stars and thin third-party coverage means fewer Stack Overflow answers; budget time to read the vendor Blade/Alpine source when something behaves oddly. That source is small and readable — treat it as part of your codebase during debugging.
  • Tailwind build time. Trimming the vendor content globs to the components you actually use (button, input, modal) measurably speeds up npm run dev on a large project.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings