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

foxws/wireui

Foxws WireUI is a Laravel and Livewire UI component library with ready-made Tailwind-styled Blade components such as buttons, modals, notifications, forms, and inputs. It helps you build interactive interfaces faster with less custom markup.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and wire up basics.

composer require foxws/wireui
php artisan wireui:install

The install command publishes config/wireui.php, the frontend assets, and (optionally) the blade component views. If it doesn't run automatically, publish manually:

php artisan vendor:publish --tag=wireui:config
php artisan vendor:publish --tag=wireui:assets
php artisan vendor:publish --tag=wireui:components   # only if you plan to override

Then in your layout (resources/views/layouts/app.blade.php), you need four things in this order:

  1. Tailwind compiled with the package's views in the content array:
    // tailwind.config.js
    content: [
      './resources/**/*.blade.php',
      './vendor/foxws/wireui/resources/**/*.blade.php',
      './vendor/foxws/wireui/src/View/**/*.php',
    ],
    
  2. Alpine.js — the package ships directives that assume Alpine 3 is loaded (Livewire 3 bundles it; Livewire 2 needs it added explicitly).
  3. The package's script/style tags inside <head> / before </body>:
    @wireUiScripts
    
  4. Your normal @livewireStyles / @livewireScripts.

First use case — notifications, because it's the smallest surface and validates the whole toolchain. From a Livewire component:

$this->notification()->success('Saved', 'Record updated.');

or from a controller:

Notification::success('Saved')->send();

If the toast appears with correct colours and dismisses cleanly, your Tailwind content paths, Alpine load, and script tag are all correct. That's the smoke test before you touch modals or form components.

Where to look first:

  • config/wireui.php — notification position, colour palettes, modal defaults, dark-mode class.
  • vendor/foxws/wireui/src/View/Components/ — every available <x-...> component and its props.
  • resources/views/components/ in the vendor dir — copy any view you want to override into resources/views/vendor/wireui/components/.

Implementation Patterns

1. Component-first UI, no bespoke JS

The core value is that every interactive primitive is a Blade component you don't have to write JS for:

<x-button primary label="Save" wire:click="save" />
<x-input wire:model="email" label="Email" />
<x-select wire:model="role" :options="$roles" />
<x-datetime-picker wire:model="starts_at" />
<x-modal-card title="Edit user" wire:model="showModal"> ... </x-modal-card>

Because these are Blade components (not Livewire components), they render server-side and hydrate through Alpine — no extra roundtrip, no separate mount lifecycle. Treat them as "styled HTML with Alpine behaviour" and compose them freely inside your own Livewire views.

2. Backend-driven modals and confirmations

The package exposes Livewire traits/helpers so you never hand-roll $dispatch('open-modal'):

use WireUi\Traits\WireUiActions;

class DeleteUser extends Component
{
    use WireUiActions;

    public function confirmDelete()
    {
        $this->dialog()->confirm([
            'title'       => 'Delete user?',
            'description' => 'This cannot be undone.',
            'accept'      => ['label' => 'Delete', 'method' => 'destroy'],
            'reject'      => ['label' => 'Cancel'],
        ]);
    }

    public function destroy() { /* ... */ }
}

The method key round-trips back to your Livewire component — this is the pattern to standardise on for destructive actions. It keeps confirmation logic on the server, avoids duplicated JS, and makes the flow testable with Livewire's testing helpers (dispatch the accept event and assert).

3. Notifications as a cross-cutting concern

Wire both notification channels from the start:

  • Frontend (Livewire) — $this->notification()->success(...). Use this inside components after an action completes.
  • Backend (redirects/controllers) — Notification::success(...)->send() flashes to session and the <x-notifications> component (which must be in your layout) drains it on next render.

Keep a small Notifier service or trait wrapping these so the rest of your app doesn't import package classes directly, and so swapping the package later is a one-file change.

4. Form components + validation

These components integrate with Livewire's @error bag automatically. The main integration tip is to not fight it — let the component render errors, and only override the view when you need a different error slot:

<x-input wire:model.blur="email" label="Email" />
{{-- error shows automatically; no @error block needed --}}

Use wire:model.blur (not wire:model) on text inputs to reduce chatter, and debounce on search fields where the package's select/datatable hooks expect it.

5. Layout integration checklist

Put in your base layout once, and forget it:

<html class="{{ config('wireui.dark_mode') ? 'dark' : '' }}">
  <head>
    @vite(['resources/css/app.css'])
    @wireUiScripts
    @livewireStyles
  </head>
  <body>
    {{ $slot }}
    <x-notifications />   {{-- required for backend-sent toasts --}}
    <x-dialog />           {{-- required for confirm/dialog helpers --}}
    @livewireScripts
  </body>
</html>

The <x-notifications> and <x-dialog /> mounts are the #1 omission — helper calls silently no-op without them.


Gotchas and Tips

Alpine is a hard dependency and version-sensitive. The package is built against Alpine 3. If you're on Livewire 3 you're fine (it bundles Alpine). If you're on Livewire 2, load Alpine before @livewireScripts and do not load it twice — duplicate Alpine loads cause "Alpine: Cannot read property 'start' of undefined" and modals that open-and-instantly-close.

Tailwind content paths are the most common "it looks broken" bug. Miss the vendor path and you get unstyled toasts, invisible modal backdrops, and dropdowns with no positioning. If a component renders but looks wrong after a production build, this is the first thing to check — the dev build may have been picking it up via a broader glob that the production purge doesn't.

Re-publish after upgrading. php artisan vendor:publish --tag=wireui:assets --force after composer updates, then clear view:clear and config:clear. Stale published views are a silent source of "the fix didn't take." In CI, either don't publish (use the vendor views) or always publish with --force.

Modals and Livewire re-renders. A modal whose wire:model state lives in the Livewire component will be re-mounted on every render, which resets Alpine state inside it. If you have a nested Livewire component inside a modal, give it a stable wire:key or the modal will visibly flicker/reset on each keystroke in a sibling field.

Z-index and stacking contexts. Modals and notifications use fixed positions. If they appear behind your app shell, it's usually a transform/filter/will-change on an ancestor creating a stacking context. Fix by mounting <x-notifications>/<x-dialog> at </body> level rather than inside a container with overflow-hidden.

Customising components — prefer publishing single views over editing vendor files. Copy one file into resources/views/vendor/wireui/components/, then run php artisan view:clear. Bulk-editing vendor views survives until the next composer update and then breaks silently.

Config quirks. Notification position is wireui.notifications.position (top-right / bottom-left, etc.). Dark mode is opt-in via wireui.dark_mode = true and a dark class on <html> if you use Tailwind's class strategy — toggling one without the other gives you either no dark styles or dark styles on a light page.

Debugging a "nothing happens" click. In order: (1) is @wireUiScripts present? (2) is <x-dialog /> mounted? (3) open the browser console — Alpine will log "Component not found" if a directive fails to register. (4) php artisan view:clear and hard-reload; cached views hide directive changes.

Extension points to know. The WireUiActions trait is the intended surface for Livewire-side helpers; WireUi\View\Components\* classes are for extending a single component; events (wireui:confirm, wireui:notification-sent) are dispatched on window, so you can listen from your own JS for analytics or chained flows without patching the package.

Testing. In Livewire tests, notification calls don't assert cleanly unless you Notification::fake() (if the package wires the standard contract) or assert on $component->effects['dispatches']. Dialog confirmations are easier to test as two units: assert the dispatch happened, then call the accept method directly — don't try to simulate the Alpine click.

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.
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core