Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simple Laravel Blade Table Component With Alpine.js and TailwindCSS
{{--
Simple Example:
<x-table-simple
striped // default: false
:columns='[
[
"name" => "Name",
"field" => "name",
"columnClasses" => "", // classes to style table th
"rowClasses" => "" // classes to style table td
],
[
"name" => "Email",
"field" => "email",
"columnClasses" => "",
"rowClasses" => ""
]
]'
:rows='[
[
"name" => "Thor",
"email" => "thor@test.test"
],
[
"name" => "Loki",
"email" => "loki@test.test"
]
]'
/>
Example with Action Links:
<x-table-simple
:columns='[
[
"name" => "Name",
"field" => "name",
"columnClasses" => "", // classes to style table th
"rowClasses" => "" // classes to style table td
],
[
"name" => "Email",
"field" => "email",
"columnClasses" => "",
"rowClasses" => ""
]
]'
:rows='[
[
"name" => "Thor",
"email" => "thor@test.test"
],
[
"name" => "Loki",
"email" => "loki@test.test"
]
]'
>
<x-slot name="tableActions">
<div class="flex flex-wrap space-x-4">
<a :href="`avengers/${row.name}/show`" class="text-blue-500 underline">Edit</a>
<a :href="`avengers/${row.name}/delete`" class="text-red-500 underline">Delete</a>
</div>
</x-slot>
</x-table-simple>
Example with Eloquent Model:
// routes/web.php
Route::get('table-demo', function() {
return view('users', [
'users' => User::query()
->with('lastLogin')
->paginate(10)
->withQueryString()
->through(fn ($user) => [
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'created_at' => $user->created_at->toFormattedDateString(),
])
]);
});
// in view users.blade.php
<x-table-simple
:columns='[
[
"name" => "Email",
"field" => "email",
"columnClasses" => "",
"rowClasses" => ""
],
[
"name" => "Created_at",
"field" => "created_at",
"columnClasses" => "",
"rowClasses" => ""
]
]'
:rows="collect($users)->all()['data'] ?? []"
table-text-link-label="Name"
>
<x-slot name="tableTextLink">
<div class="flex space-x-3 items-center">
<div class="w-10">
<img :src="`https://avatars.dicebear.com/api/initials/${row.name}.svg`" alt="avatar" class="rounded object-fit" loading="lazy">
</div>
<div>
<a :href="`users/${row.id}/show`" class="text-blue-500 underline block" x-text="row.name"></a>
<div x-text="row.email" class="text-sm"></div>
</div>
</div>
</x-slot>
</x-table-simple>
--}}
@props([
'rows' => [],
'columns' => [],
'striped' => false,
'actionText' => 'Action',
'tableTextLinkLabel' => 'Link',
])
<div
x-data="{
columns: {{ collect($columns) }},
rows: {{ collect($rows) }},
isStriped: Boolean({{ $striped }})
}"
x-cloak
wire:key="{{ md5(collect($rows)) }}" // for livewire
>
<div class="mb-5 overflow-x-auto bg-white rounded-lg shadow overflow-y-auto relative">
<table class="border-collapse table-auto w-full whitespace-no-wrap bg-white table-striped relative">
<thead>
<tr class="text-left">
@isset($tableColumns)
{{ $tableColumns }}
@else
@isset($tableTextLink)
<th class="bg-gray-50 sticky top-0 border-b border-gray-100 px-6 py-3 text-gray-500 font-bold tracking-wider uppercase text-xs truncate">
{{ $tableTextLinkLabel }}
</th>
@endisset
<template x-for="column in columns">
<th
:class="`${column.columnClasses}`"
class="bg-gray-50 sticky top-0 border-b border-gray-100 px-6 py-3 text-gray-500 font-bold tracking-wider uppercase text-xs truncate"
x-text="column.name"></th>
</template>
{{-- Displays when Custom name slots for action links is shown --}}
@isset($tableActions)
<th class="bg-gray-50 sticky top-0 border-b border-gray-100 px-6 py-3 text-gray-500 font-bold tracking-wider uppercase text-xs truncate">{{ $actionText }}</th>
@endisset
@endisset
</tr>
</thead>
<tbody>
<template x-if="rows.length === 0">
@isset($empty)
{{ $empty }}
@else
<tr>
<td colspan="100%" class="text-center py-10 px-4 py-1 text-sm">
No records found
</td>
</tr>
@endisset
</template>
<template x-for="(row, rowIndex) in rows" :key="'row-' +rowIndex">
<tr :class="{'bg-gray-50': isStriped === true && ((rowIndex+1) % 2 === 0) }">
@isset($tableRows)
{{ $tableRows }}
@else
@isset($tableTextLink)
<td
class="text-gray-600 px-6 py-3 border-t border-gray-100 whitespace-nowrap">
{{ $tableTextLink }}
</td>
@endisset
<template x-for="(column, columnIndex) in columns" :key="'column-' + columnIndex">
<td
:class="`${column.rowClasses}`"
class="text-gray-600 px-6 py-3 border-t border-gray-100 whitespace-nowrap">
<div x-text="`${row[column.field]}`" class="truncate"></div>
</td>
</template>
{{-- Custom name slots for action links --}}
@isset($tableActions)
<td
class="text-gray-600 px-6 py-3 border-t border-gray-100 whitespace-nowrap">
{{ $tableActions }}
</td>
@endisset
@endisset
</tr>
</template>
</tbody>
</table>
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment