How to Create a Livewire Table in Your Laravel Application

Livewire makes is fun to create a table inside a blade. Its strength shines through especially when you want to perform actions without refreshing the page to a user.

Assuming you have got Livewire set up and know how to create a component, we will directly jump into the Livewire component controller.

As you would notice, we are creating a users table here.

The first step is to prepare the data

The below query is made for an application that has Spatie’s Laravel Permission package installed. You can customize your query as per your requirements.

$users = DB::table('users')
            ->select('users.id as userID', 'users.name', 'users.email', DB::raw('JSON_ARRAYAGG(roles.name) as roles_list'))
            ->join('model_has_roles', 'users.id', '=', 'model_has_roles.model_id')
            ->join('roles', 'roles.id', '=', 'model_has_roles.role_id')
            ->where(function($query) {
                return $query->orWhere('roles.name', 'Manager')
                ->orWhere('roles.name', 'Editor');
            })
            ->where(function($query) {
                return $query->where('users.name', 'LIKE', '%' . $this->searchTerm . '%')
                    ->orWhere('users.email', 'LIKE', '%' . $this->searchTerm . '%');
            })
            ->groupBy('users.id', 'users.name', 'users.email')
            ->paginate(8);

The query above has two things, specific to the table:

  1. It supports search on the table (that we implement with the help of a input search textbox).

#### Define a public property in the component that will wire up with the search string on the blade

As you would notice, the search term is used in the query above. The would enable the search on the table

    public $searchTerm;

#### Create search box above your table (or as per your design) in the blade

```
<input
    wire:model.delay="searchTerm"  
    type="text"  
    class="rounded text-sm focus:ring-0 focus:ring-offset-0"  
    placeholder="Search user by name, email"
>
```
  1. It supports Pagination of results that Livewire provides out of the box.

    Use WithPagination trait

    use WithPagination;

    Use pagination function on the query. Make sure you replace get() with this function at the end of the query.

    ->paginate(8);

Create the table in the blade

It is up to you how you would design your table. This is pretty straightforward where you loop with @foreach($users as $user) to render each row of the table.

<table class="min-w-max w-full table-auto">
    <thead>
        <tr class="bg-gray-200 text-gray-600 uppercase text-sm leading-normal">
            <th class="py-3 px-6 text-left">User</th>
            <th class="py-3 px-6 text-center">Email</th>
            <th class="py-3 px-6 text-center">Actions</th>
        </tr>
    </thead>
    <tbody class="text-gray-600 text-sm font-light">
    @foreach ($users as $user)
        <tr class="border-b border-gray-200 hover:bg-gray-100">
            <td class="py-3 px-6 text-left">
                <div class="flex items-center">
                    <span class="">{{ $user->name }}</span>
                </div>
            </td>

            <td class="py-3 px-6 text-center">
                <div class="flex items-center">
                    <span class="">{{ $user->email }}</span>
                </div>
            </td>
            <td class="py-3 px-6 text-center">
                <div class="flex item-center justify-center">
                    @can('deactivate user')
                        <button
                            @click="$wire.deactivateUser({{ $user->id }})"
                        >
                            <div class="w-4 mr-2 transform hover:text-indigo-500 hover:scale-110">
                                <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
                                    <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
                                </svg>
                                
                            </div>
                        </button>
                    @endcan
                </div>
            </td>
        </tr>
    @endforeach
    </tbody>
</table>

Livewire makes is very convinient to generate the links for you with the following:

$users->links()

Leverage Livewire controller functions for actions

Another great strength of a table generated by Livewire is that you can have action buttons working for you without a need for the refresh.

Create a button on the row

<button
    @click="$wire.deactivateUser({{ $user->id }})"
>
    <div class="w-4 mr-2 transform hover:text-indigo-500 hover:scale-110">
        <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
        </svg>
        
    </div>
</button>`

The controller function deactivateUser() does the magic of interacting with the backend. Livewire does the heavylifting and presents a re-rendered table to the user.