Blog

Custom table scroller actions with Alpine JS

May 31, 2023
Mack Hankins
Alpine.js, Tailwind CSS, Admin panel, Table builder

Table Scroller I needed to create a way for my users to be able to scroll the table when a lot of columns or records are visible. We utilize our tables to filter data for large exportable sets. The following is really just meant to be a jumping off point and you should customize it to fit your needs.

We'll start by creating the scroller blade view.

resources/views/table-scroller.blade.php

<div class="table-scroller-actions" x-data="{ open: false }">
<button type="button" x-on:click="open = ! open"
x-data="{ tooltip: {} }"
class="text-white p-2 bg-primary-500 hover:bg-primary-800 focus:ring-2 focus:outline-none focus:ring-primary-300
font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center mr-2"
x-init="Alpine.effect(() => {
if(open = open) {
tooltip = false
} else {
tooltip = {
content: 'Table Scroller',
theme: Alpine.store('theme') === 'light' ? 'dark' : 'light',
placement: document.dir === 'rtl' ? 'left' : 'right'
}
}
})
"
x-tooltip.html="tooltip"
>
<x-heroicon-o-switch-horizontal class="w-4 h-4"/>
</button>
<span
x-show="open"
x-transition:enter="transition ease-in duration-300"
x-transition:enter-start="opacity-0 scale-90"
x-transition:enter-end="opacity-100 scale-100"
x-transition:leave="transition ease-out duration-300"
x-transition:leave-start="opacity-100 scale-100"
x-transition:leave-end="opacity-0 scale-90"
>
<button type="button" x-on:click="window.scroll({ top:0, left:0, behavior: 'smooth'})"
class="text-white p-2 bg-primary-500 hover:bg-primary-800 focus:ring-2 focus:outline-none focus:ring-primary-300
font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center mr-2">
<x-heroicon-o-chevron-up class="w-4 h-4"/>
</button>
<button type="button" x-on:click="window.scrollTo({ top: document.body.scrollHeight, left: 0, behavior: 'smooth'})"
class="text-white p-2 bg-primary-500 hover:bg-primary-800 focus:ring-2 focus:outline-none focus:ring-primary-300
font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center mr-2">
<x-heroicon-o-chevron-down class="w-4 h-4"/>
</button>
<button type="button"
x-on:click="document.querySelector('.filament-tables-table-container').scrollBy({ left: -document.querySelector('.filament-tables-table-container').scrollWidth, behavior: 'smooth' })"
class="text-white p-2 bg-primary-500 hover:bg-primary-800 focus:ring-2 focus:outline-none focus:ring-primary-300
font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center mr-2">
<x-heroicon-o-chevron-double-left class="w-4 h-4"/>
</button>
<button type="button"
x-on:click="document.querySelector('.filament-tables-table-container').scrollBy({ left: -150, behavior: 'smooth' })"
class="text-white p-2 bg-primary-500 hover:bg-primary-800 focus:ring-2 focus:outline-none focus:ring-primary-300
font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center mr-2">
<x-heroicon-o-chevron-left class="w-4 h-4"/>
</button>
<button type="button"
x-on:click="document.querySelector('.filament-tables-table-container').scrollBy({ left: +150, behavior: 'smooth' })"
class="text-white p-2 bg-primary-500 hover:bg-primary-800 focus:ring-2 focus:outline-none focus:ring-primary-300
font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center mr-2">
<x-heroicon-o-chevron-right class="w-4 h-4"/>
</button>
<button type="button"
x-on:click="document.querySelector('.filament-tables-table-container').scrollBy({ left: +document.querySelector('.filament-tables-table-container').scrollWidth, behavior: 'smooth' })"
class="text-white p-2 bg-primary-500 hover:bg-primary-800 focus:ring-2 focus:outline-none focus:ring-primary-300
font-medium rounded-full text-sm p-2.5 text-center inline-flex items-center mr-2">
<x-heroicon-o-chevron-double-right class="w-4 h-4"/>
</button>
</span>
</div>

Next we need to tell Filament where we want the table-scroller to render using some hooks in our service provider.

app/Providers/AppServiceProvider.php

use Filament\Facades\Filament;
use Illuminate\Contracts\View\View;
 
public function boot(): void
{
Filament::registerRenderHook(
'resource.pages.list-records.table.end',
fn (): View => view('table-scroller'),
);
Filament::registerRenderHook(
'resource.relation-manager.end',
fn (): View => view('table-scroller'),
);
}

The last thing we need to do is provide some positioning via a css class. I tried to make this work with Tailwind, but this was the simplest method.

.table-scroller-actions {
position: fixed;
left: 25px;
bottom: 45px;
z-index: 1;
}

No comments yet…