Last active
November 11, 2023 11:18
-
-
Save mithicher/3a557361b8576c09c14e0995f1ce4022 to your computer and use it in GitHub Desktop.
Simple Laravel Blade Table Component With Alpine.js and TailwindCSS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{{-- | |
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