Skip to content

Instantly share code, notes, and snippets.

@mi-dexigner
Last active September 21, 2025 06:35
Show Gist options
  • Select an option

  • Save mi-dexigner/42f1ed11325c1a80dbe1c54ce16377b5 to your computer and use it in GitHub Desktop.

Select an option

Save mi-dexigner/42f1ed11325c1a80dbe1c54ce16377b5 to your computer and use it in GitHub Desktop.
Livewire Learning

Livewire Learning

Powerful, dynamic, front-end UIs without leaving PHP.

Getting Started

simple laravel project create

Installation

  • write the command livwire install
    • composer require livewire/livewire
  • remove welcome.blade.php just using this
  • welcome.blade.php
<Livewire:hello-word/>
  • then write the command

    • php artisan make:livewore hello-word
  • then open the hello-word.blade.php

this is a current time: {{ time() }}
<button wire:click="$refresh">Refresh</button>

Actions

Responding to button presses and other events in Livewire is a breeze. we'll add a button to the page and wire up functionality to it using "actions" in Livewire.

  • php artisan make:livewire Counter
  • open controller file Counter.php
class Counter extends Component
{
    public $count = 1;
    public function render()
    {
        return view('livewire.counter');
    }

    public function increment()
    {
        $this->count++;
    }
    public function decrement($by)
    {   
        $this->count = $this->count - $by;
    }
}
  • open view file counter.blade.php
<div>
   Count: {{ $count }}
   <button wire:click="increment">+</button>
    <button wire:click="decrement(2)">-</button>
</div>

Properties

Properties in Livewire allow you to store and track state in your component. This is a fundamental concept to understand when using Livewire and allows you to build forms and other interfaces with ease.

  • php artisan make:livewire Todos
  • open Todos.php
<?php

namespace App\Livewire;

use Livewire\Component;

class Todos extends Component
{
    public $todo ='';
    public $todos = [
        'Learn Livewire',
        'Build a Livewire app',
        'Profit!',
    ];
    public function add(){
        $this->todos[] = $this->todo;
        $this->reset('todo');
    }
    public function render()
    {
        return view('livewire.todos');
    }
}

Example 1

  • open todos.blade.php
<div>
    <input type="text" wire:model='todo' placeholder="Add a todo...">
    <button wire:click='add'>Add Todo</button>
    <ul>
        @foreach($todos as $todo)
            <li class="border-b py-2">{{ $todo }}</li>
        @endforeach
    </ul>
</div>

Example 2

  • open todos.blade.php
<form wire:submit='add'>
        <h2>My Todo List</h2>
    <input type="text" wire:model.live.debounce.5ms='todo' placeholder="Add a new todo..."/>
    <button type='submit'>Add Todo</button>
    </form>
    <span>Current todo: {{ $todo }}</span>
    <hr/>
    <ul>
        @foreach($todos as $todo)
            <li class="border-b py-2">{{ $todo }}</li>
        @endforeach
    </ul>

Lifecycle Hooks

Let me introduce you to a few important lifecycle hooks in Livewire. We'll cover "mount" and "updated" in this video. Both of these are useful for doing any custom initialization on a page as well as running custom code after every property update.

public function mount(){
    $this->todos =[
        'Learn Livewire',
        'Build a Livewire app',
        'Profit!',
    ];
    }

    public function updated($property,$value){
        // dd($property,$value);
        $this->$property = strtoupper($value);
    }

Page Components

So far we've built basic, standalone, components. I'll introduce you to the concept of "Page Components". These allow you to use a Livewire component as an entire page in your app. We'll cover things like routing, page layouts, and page titles.

  • php artisan livewire:layout
  • open the app.blade.php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">

        <title>{{ $title ?? 'Page Title' }}</title>
        <style>
            .current{font-weight: 700;}
        </style>
    </head>
    <body>
        <nav>
            <a href="/" @class(['current'=>request()->is('/')])>Todos</a>
            <a href="/counter" @class(['current'=>request()->is('counter')])>Clicker</a>
        </nav>
        {{ $slot }}
    </body>
</html>
  • set the routes in web.php
Route::get("/",Todos::class);
Route::get("/counter",Clicker::class);

Basic Table

Before we go any further, let's build a basic table with data from an Eloquent model. Livewire makes it easy to display data as rows in a table and add things like "delete" buttons to each row.

Example in view

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    @foreach ($this->users as $user)
      <tr wire:key="{{ $user->id }}">
      <td>{{ $user->name }}</td>
    <td>{{ $user->email }}</td>
    <td><button type="button" wire:click="delete({{ $user->id }})" wire:confirm="Are you sure want to delete this??">Delete</button></td>
    </tr>
    @endforeach
  </tbody>
 </table>

Example in Controller

public function delete(User $user){
        $user->delete();
    }

Basic Form

If tables are one essential component in every app, forms are the other. we'll walk through building a basic form in your application. We'll cover all the essentials from validation, to submission, to redirecting after.

Example controller

// #[Rule('required',as: 'Title')]
    #[Rule('required',message: 'Yo, add a Name')]
    #[Rule('min:4',message: 'Yo, too short')]
    public $name = '';
    #[Rule('required|email|max:30|unique:users')]
    public $email;
    #[Rule('required|min:5|max:16')]
    public $password;

  public function save(){
        $this->validate();
        User::create([
            'name'=>$this->name,
            'email'=>$this->email,
            'password'=>$this->password
        ]);
        $this->redirect('/');
        // dd("saved!");
    }

Example view

<form wire:submit="save">
  <label>
    <span>Name</span>
    <input type="text" placeholder="Name" id="name" wire:model="name" />
  @error('name')
     <em>{{ $message }}</em>
  @enderror
  </label>
  <label>
    <span>E-mail</span>
    <input type="email" placeholder="E-Mail" id="" wire:model="email" />
  @error('email')
     <em>{{ $message }}</em>
  @enderror
  </label>
  <input type="password" placeholder="Password" id="password" wire:model="password" />
  @error('password')
     <em>{{ $message }}</em>
  @enderror
  <button type="submit"><span>Submit</span></button>
 </form>

Alpine

AlpineJS is the front-end companion framework that comes bundled with every Livewire application. In fact, Livewire's front-end is built on top of Alpine itself. We'll walk through a few common use cases and how you can use Alpine to add interactivity into your Livewire components without making server roundtrips.

Example View for Master layout file

<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>{{ $title ?? 'Page Title' }}</title>
         @livewireStyles
    </head>
    <body>
       
        {{ $slot }}
        @livewireScripts
    </body>
</html>

Example View Alpine Scripts work

<div x-data="{count:0}">
    <span x-text="count"></span>
    <button x-on:click="count++">+</button>
  </div>

  <h3>Current Name: <em x-text="$wire.name.length"></em></h3>
 <button x-on:click="$wire.name=''">Clear Name</button>
 <button x-on:click="$wire.save()">Submit Form</button>
 {{-- <form wire:submit="save"> --}}
 <form x-on:submit="$wire.save()">
  <label>
    <span>Name</span>
    <input type="text" placeholder="Name" id="name" wire:model="name" />
    <small>Words:<span x-text="$wire.name.split(' ').length - 1"></span></small>
  @error('name')
     <em>{{ $message }}</em>
  @enderror
  </label>
  <label>
    <span>E-mail</span>
    <input type="email" placeholder="E-Mail" id="" wire:model="email" />
    <small>Characters:<span x-text="$wire.email.length">0</span></small>
  @error('email')
     <em>{{ $message }}</em>
  @enderror
  </label>
  <input type="password" placeholder="Password" id="password" wire:model="password" />
  @error('password')
     <em>{{ $message }}</em>
  @enderror
  <button type="submit"><span>Submit</span></button>
 </form>

Testing

Livewire provides lots of helpful tools for building automated tests for your components. we'll build a few basic tests for the form component we built earlier.

  • php artisan make:livewire create-post --test
  • vscode extension Better PHPUnit

Nesting

Livewire allows you to nest components within each other. This is an extremely powerful technique, however, there are important cavaets and knowledge to be aware of when nesting.

  • php artisan make:livewire user-row
  • open the user.blade.php
<table cellspacing="0" cellpadding="10" border="1">
  <thead>
    <tr>
      <th>Name</th>
      <th>Email</th>
      <th></th>
    </tr>
  </thead>
  <tbody>
    @foreach ($users as $user)
    <livewire:user-row :key="$user->id" :user="$user" />
    @endforeach
  </tbody>
 </table>
  • open the controller for UserRow.php
<?php

namespace App\Livewire;

use Livewire\Component;

class UserRow extends Component
{
    public $user;
    public function mount($user){
        $this->user = $user;
    }


    public function archive(){
        $this->user;
    }

    public function render()
    {
        return view('livewire.user-row');
    }
}
  • open the view for user-row.php
 <tr @class(['archive'=>$user->is_archive])>
      <td>{{ $user->name }}</td>
    <td>{{ $user->email }}</td>
   <td>
    @unless ($user->is_archive)
    <button type="button" wire:click="archive" wire:confirm="Are you sure want to Archive this??">Archive</button>
    @endunless
    <button type="button" wire:click="$parent.delete({{ $user->id }})" wire:confirm="Are you sure want to delete this??">Delete</button></td>
</tr>

Navigate

Before we tie up this series, let's see how we can turn our simple Laravel application into an "SPA" (Single page application) by adding the wire:navigate directive to our navigation links.

<nav>
            <a wire:navigate href="/todos" @class(['current'=>request()->is('/')])>Todos</a>
            <a wire:navigate href="/" @class(['current'=>request()->is('counter')])>Clicker</a>

Controller using redirect

public function save(){
        $this->validate();
        User::create([
            'name'=>$this->name,
            'email'=>$this->email,
            'password'=>$this->password
        ]);
        $this->redirect('/todos',navigate:true);
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment