Features of a Livewire project: Livewire, volt, flux, Alpine...

Video thumbnail

Before starting to develop our application in Livewire, once the project in Laravel Livewire has been created, I want to take a short break to tell you what we have in a project with this framework.

In a nutshell, we can say that Livewire are “boosted” Laravel components. That is, with these components we can perform multiple operations that would normally require much more code or additional configurations.

When you start a project with Laravel Livewire, especially from version 12 onwards, you quickly discover that you are not working with “traditional Laravel,” but with something that—as happened to me the first time—feels like boosted Laravel components. In this article, I explain, from a practical perspective, what the real characteristics of a modern Livewire project are, how it is built, what it includes, what changes compared to previous versions, and how to get the most out of it.

We're going to talk about the most important aspects we have when creating a project in Laravel Livewire starting from version 12 of Laravel, which, as we mentioned before, unlike previous versions, no longer includes the functionalities we had in previous versions with Jetstream.

What Livewire allows

With Livewire components we can:

  • Perform view routing: instead of a controller returning a view, we can do it using a component.
  • Use dynamic properties, similar to Vue's v-model, to reactively link data between the frontend and the backend.
  • Work with query strings to keep information in the URL and synchronize it with the component's state.
  • Handle file uploads easily.
  • And many other operations that we will see in practice.

I don't want to get too far ahead, because some functions are more technical, and it's better to explore them directly while building our application.

The important thing is to take away the idea: Livewire gives us improved Laravel components, with many ready-to-use functionalities, which allows us to develop dynamic applications without leaving the Laravel ecosystem.

Why choose Livewire for your Laravel project?

Livewire has positioned itself as a perfect intermediate solution between traditional Blade and SPA frameworks like Vue or React. It's ideal for those who want reactive interfaces without having to set up an entire modern JavaScript infrastructure.

In my first Livewire projects, one of the things that surprised me the most was being able to perform instant actions with wire:model, wire:click, or even manage Query Strings without writing a single line of JS. You literally connect a property to the view and the state flows.

Main advantages to highlight:

  • Elimination of complex JS for most interactions.
  • 100% native integration with Blade.
  • Reusable and nested components.
  • Lazy loading, instant validation, file uploads.
  • Ideal for panels, dashboards, CRUDs, and internal tools.

Essential elements of a Livewire project

Folder structure and components

A Livewire project in Laravel 12 is based on the idea that every part of your interface is a component. This includes forms, dashboards, sidebars, profiles, and any element that needs logic and a view.

In my first steps, I noticed that, unlike previous versions, the direct Livewire dependency no longer appears in composer.json: it now arrives through packages like Volt and Flux, which changes the project's architecture.

If you review the structure of a freshly installed Livewire project, you'll notice:

  • /app/Livewire → where the components live
  • /resources/views/livewire → Blade views of each component
  • /resources/views/components → auxiliary Blade components
  • /routes/web.php → routes that can point directly to Livewire components

It's common to see routes like:

Route::get('/dashboard', \App\Livewire\Dashboard::class);

Key dependencies: Volt, Flux, and more

In Livewire 12+, the ecosystem is reinforced with:

Volt

Volt allows building logic and view in a single file, something that feels almost like Svelte or Vue Single File Components, but directly in Blade.

A typical example:

<?php
use function Livewire\Volt\{state};
state(['count' => 0]);
$increment = fn () => $this->count++;
?>
<div>
  <h1>{{ $count }}</h1>
  <button wire:click="increment">+</button>
</div>

Volt is not one of my favorite technologies, as I don't like mixing logic with presentation, and in Livewire 4 we will even have a third way to create components in Livewire; even so, it is a completely valid structure.

Laravel Volt

In recent Laravel Livewire projects, starting from Laravel version 12, creating a project in Laravel Livewire includes other technologies such as:

Volt:

https://livewire.laravel.com/docs/volt

With which, we can create both the logic and the view (blade) in a single file:

<?php

use function Livewire\Volt\{state};

state(['count' => 0]);

$increment = fn () => $this->count++;

?>

<div>
   <h1>{{ $count }}</h1>
   <button wire:click="increment">+</button>
</div>

Laravel Flux UI

We will also see that the auxiliary components we use now are not the same as before; we now use Flux.

Flux, which is nothing more than a library of ready-to-use components for Laravel Livewire:

https://fluxui.dev/

<flux:input
   wire:model="email"
   :label="__('Email address')"
   type="email"
   required
   autocomplete="email"
   placeholder="email@example.com"
/>

Which you can expose to customize:

$ php artisan flux:publish

We also see a more complex structure, such as not having the Livewire dependency in composer.json, but rather the previous packages that import Livewire as a dependency.

Flux is a library of pre-built UI components that Livewire integrates to speed up development; it really has very good components. It is a freemium type, meaning it has free and paid components.

Components like:

<flux:input>
<flux:navlist>
<flux:dropdown>
<flux:menu>
<flux:profile>

For example:

<flux:input
  wire:model="email"
  label="Email"
  type="email"
  required
/>

These are Laravel components with tons of Tailwind classes, easy to extend:

$ php artisan flux:publish

With the command above, you can publish ALL flux components to analyze them.

Data-binding, props, and events (wire:model, actions)

Livewire allows views and logic to stay automatically synchronized.
Examples:

  • wire:model="email" keeps the state between input and component.
  • wire:click="save" executes backend methods without reloading.
  • wire:loading handles loading states.
  • wire:keyup.debounce.500ms optimizes events.

For me, the BEST thing about Livewire is wire:click.

Routing, views, and single page (without traditional controller)

A Livewire component can replace a controller.
Classic example:

class Dashboard extends Component {
  public function render() {
     return view('livewire.dashboard');
  }
}

This simplifies the architecture by more than 40% in small/medium projects.

File upload, real-time validation, and lazy loading

Advanced Livewire features that are often highlights of the framework:

  • File upload with prior validation.
  • Instant validation with server rules.
  • Lazy loading for components that shouldn't load on startup.
  • Query Strings synchronizable with internal properties: useful for filters, tables, pagination.

When I implemented file uploads for the first time, I was surprised that I didn't have to write any JS for previews and states.

Analyzing a Livewire project

The route points directly to the component, without going through a traditional controller. The first time I did it, I thought, "wow, this simplifies tons of boilerplate."

But that's just the beginning. The most important thing is to understand how a modern Livewire project is structured, so let's get to that.

The first thing we see is a couple of links for registration and login; at this point, if you haven't already, create a user; once registered or logged in, you will have access to:

http://livewirestore.test/dashboard

Whose view corresponds to:

<x-layouts.app title="Dashboard">
   <div class="flex h-full w-full flex-1 flex-col gap-4 rounded-xl">
       <div class="grid auto-rows-min gap-4 md:grid-cols-3">
           <div class="relative aspect-video overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700">
               <x-placeholder-pattern class="absolute inset-0 size-full stroke-gray-900/20 dark:stroke-neutral-100/20" />
           </div>
           <div class="relative aspect-video overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700">
               <x-placeholder-pattern class="absolute inset-0 size-full stroke-gray-900/20 dark:stroke-neutral-100/20" />
           </div>
           <div class="relative aspect-video overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700">
               <x-placeholder-pattern class="absolute inset-0 size-full stroke-gray-900/20 dark:stroke-neutral-100/20" />
           </div>
       </div>
       <div class="relative h-full flex-1 overflow-hidden rounded-xl border border-neutral-200 dark:border-neutral-700">
           <x-placeholder-pattern class="absolute inset-0 size-full stroke-gray-900/20 dark:stroke-neutral-100/20" />
       </div>
   </div>
</x-layouts.app>

As you can appreciate, x-layout-app corresponds to a base Laravel component:

resources/views/components/layouts/app.blade.php

<x-layouts.app.sidebar :title="$title ?? null">
   <flux:main>
       {{ $slot }}
   </flux:main>
</x-layouts.app.sidebar>

The strangest part of the previous code is the component that starts with flux, which are the components mentioned at the beginning provided by the Livewire Flux package. There are many of them throughout the application that serve different purposes, but their suffix already quite well exemplifies what they do, for example:

<flux:navlist>
<flux:navlist.item>
<flux:heading>
<flux:subheading>
<flux:dropdown>
<flux:profile>
<flux:menu>
<flux:input>

In the end, all of these are nothing more than Laravel components with a lot of Tailwind classes, so you can inspect them from the browser; similarly, we will be using these components little by little as we progress.

resources/views/components/layouts/app/sidebar.blade.php

<flux:sidebar sticky stashable class="border-r border-zinc-200 bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900">

The rest of the available actions created by the Laravel installer include actions like changing the password and other user data, closing the account, dark mode, and little else; you have this listed in the sidebar below:

http://livewirestore.test/settings/profile

Best practices you should follow

Performance and lazy loading

  • Use lazy when possible (wire:model.lazy).
  • Divide large components into subcomponents.
  • Avoid unnecessary renders using ->skipRender().
  • Load scripts only when needed.

SEO, accessibility, and user experience

Although Livewire is not a complete SPA framework, it does support:

  • dynamic metas
  • page titles
  • fast navigation
  • accessible components (especially with Flux UI)

You can really use aspects of Livewire along with classic Laravel, and this website is an example of that: I use Laravel Livewire for the Dashboard, and base Laravel for the blog.

Testing, maintenance, and scalability

  • Use tests with Livewire::test().
  • Maintain consistent naming between components and views.
  • Version UI components.
  • Avoid mixing too much logic into a single component (maximum 1 responsibility).

In summary: working with Livewire today feels modern, flexible, and much simpler than before, although unfortunately, pre-defined options previously available with Jetstream, such as avatar upload, session, roles/teams, are no longer included.

FAQs: Frequently Asked Questions about Livewire projects

  • Does Livewire replace Vue or React?
    • It depends on the type of project: for internal panels and CRUDs, yes; for ultra-interactive apps, no.
  • Can I use it along with Alpine.js?
    • Yes, it's a very common combination.
  • Is it suitable for large projects?
    • Yes, especially with well-divided components. The community on Reddit shares good experiences in medium/large projects.
  • What changes in Laravel 12?
    • Volt and Flux become part of the modern Livewire ecosystem, and Jetstream no longer includes as many predefined features.

Now, let's get to know the key piece of Livewire, the components.

I agree to receive announcements of interest about this Blog.

We are going to present what we have in detail, the project, its characteristics and how it works.

| 👤 Andrés Cruz

🇪🇸 En español