Tune it live. Every preset is pure CSS variables.
"Default" follows the body font.
Copy your complete theme and paste it as your resources/css/app.css — the Tailwind import, every token and the @theme mapping are all included, so it works as-is.
Every BlatUI form control is Livewire-ready. Bind wire:model to
any of them — inputs, selects, checkboxes, switches, sliders, rich text, date & file pickers —
and get real two-way binding. No wrappers, no second library, and you still own every line.
BlatUI components are plain Blade + Alpine, so they already render inside Livewire components.
Install Livewire as usual, then use BlatUI tags in any Livewire view — the
wire:model bridge activates automatically when Livewire is present and stays
completely inert when it isn't (your non-Livewire pages are unaffected).
composer require livewire/livewire
wire:model
Drop wire:model onto any form control exactly like a native input. Native fields
(input, textarea, native select) bind directly; the rich
Alpine widgets (custom select, combobox, switch, slider, rating, color/date/time
pickers, tags, OTP, knob…) entangle their internal state with your Livewire
property — so server and client stay in sync both ways.
use Livewire\Component;
class ProfileForm extends Component
{
public string $name = '';
public string $plan = 'pro';
public bool $notify = true;
public array $tags = [];
public int $volume = 30;
public function render()
{
return view('livewire.profile-form');
}
}
<form wire:submit="save" class="space-y-4">
<x-ui.input wire:model="name" placeholder="Full name" />
<x-ui.select wire:model="plan" :options="['free' => 'Free', 'pro' => 'Pro']" />
<x-ui.switch wire:model="notify" />
<x-ui.tags-input wire:model="tags" />
<x-ui.slider wire:model="volume" />
<x-ui.button type="submit">Save</x-ui.button>
</form>
All the usual wire:model modifiers work. By default binding is deferred (synced on
the next request); add .live for real-time updates, or .blur /
.debounce as needed.
<x-ui.input wire:model="search" />
<x-ui.input wire:model.live="search" />
<x-ui.input wire:model.live.debounce.400ms="search" />
BlatUI fields already render aria-invalid styling. Pair Livewire's
@error with the aria-invalid attribute and the
built-in field components to surface messages.
<x-ui.field>
<x-ui.field-label for="email">Email</x-ui.field-label>
<x-ui.input id="email" type="email" wire:model="email"
aria-invalid="{{ $errors->has('email') ? 'true' : 'false' }}" />
@error('email')
<x-ui.field-error>{{ $message }}</x-ui.field-error>
@enderror
</x-ui.field>
Because the components are real DOM, Livewire's wire:loading and
wire:target work directly on them.
<x-ui.button type="submit">
<span wire:loading.remove wire:target="save">Save</span>
<span wire:loading wire:target="save" class="inline-flex items-center gap-2">
<x-ui.spinner class="size-4" /> Saving…
</span>
</x-ui.button>
The file-upload component forwards wire:model onto its real
<input type="file">, so Livewire's
temporary file uploads
work out of the box (use the WithFileUploads trait).
<x-ui.file-upload wire:model="avatar" accept="image/*" />
wire:model is supported on every value-bearing component:
Note: slider, date-picker and datetime-picker bind a single
value in their default (single) mode; their range modes submit via standard
name[...] form fields.
BlatUI ships everything Flux Pro charges for — calendar, charts, command palette, date & time pickers, editor, listbox/combobox, file upload, kanban and more — plus 60+ extra components, blocks and charts. The difference: BlatUI is MIT-licensed and free, and the components are copied into your project, so you own and can edit every line.
you own the code
no per-project license
works with or without Livewire