Skip to content

Instantly share code, notes, and snippets.

@vlados
Created September 2, 2025 19:55
Show Gist options
  • Save vlados/43baed3424f9b181026e195af9619f66 to your computer and use it in GitHub Desktop.
Save vlados/43baed3424f9b181026e195af9619f66 to your computer and use it in GitHub Desktop.
filament floating toolbar
@import '../../../../vendor/filament/filament/resources/css/theme.css';
@source '../../../../app/Filament/**/*';
@source '../../../../resources/views/filament/**/*';
.fi-body {
@apply bg-white;
}
.fi-sidebar-nav-groups {
@apply gap-0;
}
.fi-sidebar-group-label {
@apply text-xs;
}
.fi-sidebar-item {
.fi-sidebar-item-btn {
@apply p-1.5 ;
}
.fi-badge {
display: block;
padding: 2px 7px;
}
.fi-sidebar-item-label {
@apply text-black;
}
.fi-icon {
@apply size-4 text-black;
}
}
.fi-page-header-main-ctn {
@apply gap-y-4 pt-4;
}
.fi-header-heading {
@apply text-black text-2xl;
}
.fi-ta-ctn {
@apply ring-0 shadow-none;
:where(& > :not(:last-child)) {
@apply border-0;
}
}
.fi-ta-content-ctn {
.fi-ta-header-cell {
@apply p-2.5;
}
@apply border rounded-lg;
}
.fi-ta-cell {
&:last-of-type,
&.fi-ta-selection-cell:first-of-type {
@apply p-2;
}
}
.fi-ta-text-item {
&.fi-size-sm {
@apply p-2.5;
}
}
.fi-ta-selection-indicator {
@apply shadow-xl rounded-xl fixed bottom-10 left-1/2 -translate-x-1/2 z-10 flex items-center gap-x-2 border bg-gray-900 text-white p-2 px-2;
.fi-dropdown-panel {
@apply !absolute;
}
& > :nth-child(1) {
@apply text-white;
}
}
@php
use Filament\Support\Enums\Alignment;
use Filament\Support\Enums\VerticalAlignment;
use Filament\Support\Enums\Width;
use Filament\Support\Facades\FilamentView;
use Filament\Tables\Actions\HeaderActionsPosition;
use Filament\Tables\Columns\Column;
use Filament\Tables\Columns\ColumnGroup;
use Filament\Tables\Enums\FiltersLayout;
use Filament\Tables\Enums\RecordActionsPosition;
use Filament\Tables\Enums\RecordCheckboxPosition;
use Filament\Tables\View\TablesRenderHook;
use Illuminate\Support\Str;
use Illuminate\View\ComponentAttributeBag;
$defaultRecordActions = $getRecordActions();
$flatRecordActionsCount = count($getFlatRecordActions());
$recordActionsAlignment = $getRecordActionsAlignment();
$recordActionsPosition = $getRecordActionsPosition();
$recordActionsColumnLabel = $getRecordActionsColumnLabel();
if (! $recordActionsAlignment instanceof Alignment) {
$recordActionsAlignment = filled($recordActionsAlignment) ? (Alignment::tryFrom($recordActionsAlignment) ?? $recordActionsAlignment) : null;
}
$activeFiltersCount = $getActiveFiltersCount();
$isSelectionDisabled = $isSelectionDisabled();
$maxSelectableRecords = $getMaxSelectableRecords();
$columns = $getVisibleColumns();
$collapsibleColumnsLayout = $getCollapsibleColumnsLayout();
$columnsLayout = $getColumnsLayout();
$content = $getContent();
$contentGrid = $getContentGrid();
$contentFooter = $getContentFooter();
$filterIndicators = $getFilterIndicators();
$filtersApplyAction = $getFiltersApplyAction();
$filtersForm = $getFiltersForm();
$filtersFormWidth = $getFiltersFormWidth();
$hasColumnGroups = $hasColumnGroups();
$hasColumnsLayout = $hasColumnsLayout();
$hasSummary = $hasSummary($this->getAllTableSummaryQuery());
$header = $getHeader();
$headerActions = array_filter(
$getHeaderActions(),
fn (\Filament\Actions\Action | \Filament\Actions\ActionGroup $action): bool => $action->isVisible(),
);
$headerActionsPosition = $getHeaderActionsPosition();
$heading = $getHeading();
$group = $getGrouping();
$toolbarActions = array_filter(
$getToolbarActions(),
fn (\Filament\Actions\Action | \Filament\Actions\ActionGroup $action): bool => $action->isVisible(),
);
$hasNonBulkToolbarAction = false;
foreach ($toolbarActions as $toolbarAction) {
if ($toolbarAction instanceof \Filament\Actions\BulkActionGroup) {
continue;
}
if ($toolbarAction instanceof \Filament\Actions\ActionGroup) {
if ($toolbarAction->hasNonBulkAction()) {
$hasNonBulkToolbarAction = true;
break;
}
continue;
}
if (! $toolbarAction->isBulk()) {
$hasNonBulkToolbarAction = true;
break;
}
}
$groups = $getGroups();
$description = $getDescription();
$isGroupsOnly = $isGroupsOnly() && $group;
$isReorderable = $isReorderable();
$isReordering = $isReordering();
$areGroupingSettingsVisible = (! $isReordering) && count($groups) && (! $areGroupingSettingsHidden());
$isGroupingDirectionSettingHidden = $isGroupingDirectionSettingHidden();
$areGroupingSettingsInDropdownOnDesktop = $areGroupingSettingsInDropdownOnDesktop();
$isColumnSearchVisible = $isSearchableByColumn();
$isGlobalSearchVisible = $isSearchable();
$isSearchOnBlur = $isSearchOnBlur();
$isSelectionEnabled = $isSelectionEnabled() && (! $isGroupsOnly);
$selectsCurrentPageOnly = $selectsCurrentPageOnly();
$recordCheckboxPosition = $getRecordCheckboxPosition();
$isStriped = $isStriped();
$isLoaded = $isLoaded();
$hasFilters = $isFilterable();
$filtersLayout = $getFiltersLayout();
$filtersTriggerAction = $getFiltersTriggerAction();
$hasFiltersDialog = $hasFilters && in_array($filtersLayout, [FiltersLayout::Dropdown, FiltersLayout::Modal]);
$hasFiltersAboveContent = $hasFilters && in_array($filtersLayout, [FiltersLayout::AboveContent, FiltersLayout::AboveContentCollapsible]);
$hasFiltersAboveContentCollapsible = $hasFilters && ($filtersLayout === FiltersLayout::AboveContentCollapsible);
$hasFiltersBelowContent = $hasFilters && ($filtersLayout === FiltersLayout::BelowContent);
$hasColumnManagerDropdown = $hasColumnManager();
$hasReorderableColumns = $hasReorderableColumns();
$hasToggleableColumns = $hasToggleableColumns();
$columnManagerApplyAction = $getColumnManagerApplyAction();
$columnManagerTriggerAction = $getColumnManagerTriggerAction();
$hasHeader = $header || $heading || $description || ($headerActions && (! $isReordering)) || $isReorderable || $areGroupingSettingsVisible || $isGlobalSearchVisible || $hasFilters || count($filterIndicators) || $hasColumnManagerDropdown;
$hasHeaderToolbar = $isReorderable || $areGroupingSettingsVisible || $isGlobalSearchVisible || $hasFiltersDialog || $hasColumnManagerDropdown;
$headingTag = $getHeadingTag();
$secondLevelHeadingTag = $heading ? $getHeadingTag(1) : $headingTag;
$pluralModelLabel = $getPluralModelLabel();
$records = $isLoaded ? $getRecords() : null;
$searchDebounce = $getSearchDebounce();
$allSelectableRecordsCount = ($isSelectionEnabled && $isLoaded) ? $getAllSelectableRecordsCount() : null;
$columnsCount = count($columns);
$reorderRecordsTriggerAction = $getReorderRecordsTriggerAction($isReordering);
$page = $this->getTablePage();
$defaultSortOptionLabel = $getDefaultSortOptionLabel();
$sortDirection = $getSortDirection();
if (count($defaultRecordActions) && (! $isReordering)) {
$columnsCount++;
}
if ($isSelectionEnabled || $isReordering) {
$columnsCount++;
}
if ($group) {
$groupedSummarySelectedState = $this->getTableSummarySelectedState($this->getAllTableSummaryQuery(), modifyQueryUsing: fn (\Illuminate\Database\Query\Builder $query) => $group->groupQuery($query, model: $getQuery()->getModel()));
}
@endphp
<div
@if (! $isLoaded)
wire:init="loadTable"
@endif
x-data="filamentTable({
canTrackDeselectedRecords: @js($canTrackDeselectedRecords()),
currentSelectionLivewireProperty: @js($getCurrentSelectionLivewireProperty()),
maxSelectableRecords: @js($maxSelectableRecords),
selectsCurrentPageOnly: @js($selectsCurrentPageOnly),
$wire,
})"
{{
$getExtraAttributeBag()->class([
'fi-ta',
'fi-loading' => $records === null,
])
}}
>
<input
type="hidden"
value="{{ $allSelectableRecordsCount }}"
x-ref="allSelectableRecordsCount"
/>
<div
@class([
'fi-ta-ctn',
'fi-ta-ctn-with-header' => $hasHeader,
])
>
<div
@if (! $hasHeader) x-cloak @endif
x-show="@js($hasHeader) || @js($hasNonBulkToolbarAction) || (getSelectedRecordsCount() && @js(count($toolbarActions)))"
class="fi-ta-header-ctn"
>
{{ FilamentView::renderHook(TablesRenderHook::HEADER_BEFORE, scopes: static::class) }}
@if ($header)
{{ $header }}
@elseif (($heading || $description || $headerActions) && ! $isReordering)
<div
@class([
'fi-ta-header',
'fi-ta-header-adaptive-actions-position' => $headerActions && ($headerActionsPosition === HeaderActionsPosition::Adaptive),
])
>
@if ($heading || $description)
<div>
@if ($heading)
<{{ $headingTag }}
class="fi-ta-header-heading"
>
{{ $heading }}
</{{ $headingTag }}>
@endif
@if ($description)
<p class="fi-ta-header-description">
{{ $description }}
</p>
@endif
</div>
@endif
@if ((! $isReordering) && $headerActions)
<div class="fi-ta-actions fi-align-start fi-wrapped">
@foreach ($headerActions as $action)
{{ $action }}
@endforeach
</div>
@endif
</div>
@endif
{{ FilamentView::renderHook(TablesRenderHook::HEADER_AFTER, scopes: static::class) }}
@if ($hasFiltersAboveContent)
<div
x-data="{ areFiltersOpen: @js(! $hasFiltersAboveContentCollapsible) }"
x-bind:class="{ 'fi-open': areFiltersOpen }"
@class([
'fi-ta-filters-above-content-ctn',
])
>
<x-filament-tables::filters
:apply-action="$filtersApplyAction"
:form="$filtersForm"
:heading-tag="$secondLevelHeadingTag"
x-cloak
x-show="areFiltersOpen"
/>
@if ($hasFiltersAboveContentCollapsible)
<span
x-on:click="areFiltersOpen = ! areFiltersOpen"
class="fi-ta-filters-trigger-action-ctn"
>
{{ $filtersTriggerAction->badge($activeFiltersCount) }}
</span>
@endif
</div>
@endif
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_BEFORE, scopes: static::class) }}
<div
@if (! $hasHeaderToolbar) x-cloak @endif
x-show="@js($hasHeaderToolbar) || @js($hasNonBulkToolbarAction) || (getSelectedRecordsCount() && @js(count($toolbarActions)))"
class="fi-ta-header-toolbar"
>
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_START, scopes: static::class) }}
@if ($isGlobalSearchVisible || $hasFiltersDialog || $hasColumnManagerDropdown)
<div>
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_SEARCH_BEFORE, scopes: static::class) }}
@if ($isGlobalSearchVisible)
@php
$searchPlaceholder = $getSearchPlaceholder();
@endphp
<x-filament-tables::search-field
:debounce="$searchDebounce"
:on-blur="$isSearchOnBlur"
:placeholder="$searchPlaceholder"
/>
@endif
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_SEARCH_AFTER, scopes: static::class) }}
@if ($hasFiltersDialog || $hasColumnManagerDropdown)
@if ($hasFiltersDialog)
@if (($filtersLayout === FiltersLayout::Modal) || $filtersTriggerAction->isModalSlideOver())
@php
$filtersTriggerActionModalAlignment = $filtersTriggerAction->getModalAlignment();
$filtersTriggerActionIsModalAutofocused = $filtersTriggerAction->isModalAutofocused();
$filtersTriggerActionHasModalCloseButton = $filtersTriggerAction->hasModalCloseButton();
$filtersTriggerActionIsModalClosedByClickingAway = $filtersTriggerAction->isModalClosedByClickingAway();
$filtersTriggerActionIsModalClosedByEscaping = $filtersTriggerAction->isModalClosedByEscaping();
$filtersTriggerActionModalDescription = $filtersTriggerAction->getModalDescription();
$filtersTriggerActionVisibleModalFooterActions = $filtersTriggerAction->getVisibleModalFooterActions();
$filtersTriggerActionModalFooterActionsAlignment = $filtersTriggerAction->getModalFooterActionsAlignment();
$filtersTriggerActionModalHeading = $filtersTriggerAction->getCustomModalHeading() ?? __('filament-tables::table.filters.heading');
$filtersTriggerActionModalIcon = $filtersTriggerAction->getModalIcon();
$filtersTriggerActionModalIconColor = $filtersTriggerAction->getModalIconColor();
$filtersTriggerActionIsModalSlideOver = $filtersTriggerAction->isModalSlideOver();
$filtersTriggerActionIsModalFooterSticky = $filtersTriggerAction->isModalFooterSticky();
$filtersTriggerActionIsModalHeaderSticky = $filtersTriggerAction->isModalHeaderSticky();
@endphp
<x-filament::modal
:alignment="$filtersTriggerActionModalAlignment"
:autofocus="$filtersTriggerActionIsModalAutofocused"
:close-button="$filtersTriggerActionHasModalCloseButton"
:close-by-clicking-away="$filtersTriggerActionIsModalClosedByClickingAway"
:close-by-escaping="$filtersTriggerActionIsModalClosedByEscaping"
:description="$filtersTriggerActionModalDescription"
:footer-actions="$filtersTriggerActionVisibleModalFooterActions"
:footer-actions-alignment="$filtersTriggerActionModalFooterActionsAlignment"
:heading="$filtersTriggerActionModalHeading"
:icon="$filtersTriggerActionModalIcon"
:icon-color="$filtersTriggerActionModalIconColor"
:slide-over="$filtersTriggerActionIsModalSlideOver"
:sticky-footer="$filtersTriggerActionIsModalFooterSticky"
:sticky-header="$filtersTriggerActionIsModalHeaderSticky"
:width="$filtersFormWidth"
:wire:key="$this->getId() . '.table.filters'"
class="fi-ta-filters-modal"
>
<x-slot name="trigger">
{{ $filtersTriggerAction->badge($activeFiltersCount) }}
</x-slot>
{{ $filtersTriggerAction->getModalContent() }}
{{ $filtersForm }}
{{ $filtersTriggerAction->getModalContentFooter() }}
</x-filament::modal>
@else
@php
$filtersFormMaxHeight = $getFiltersFormMaxHeight();
@endphp
<x-filament::dropdown
:max-height="$filtersFormMaxHeight"
placement="bottom-end"
shift
:width="$filtersFormWidth ?? Width::ExtraSmall"
:wire:key="$this->getId() . '.table.filters'"
class="fi-ta-filters-dropdown"
>
<x-slot name="trigger">
{{ $filtersTriggerAction->badge($activeFiltersCount) }}
</x-slot>
<x-filament-tables::filters
:apply-action="$filtersApplyAction"
:form="$filtersForm"
:heading-tag="$secondLevelHeadingTag"
/>
</x-filament::dropdown>
@endif
@endif
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_BEFORE, scopes: static::class) }}
@if ($hasColumnManagerDropdown)
@php
$columnManagerMaxHeight = $getColumnManagerMaxHeight();
$columnManagerWidth = $getColumnManagerWidth();
$columnManagerColumns = $getColumnManagerColumns();
@endphp
<x-filament::dropdown
:max-height="$columnManagerMaxHeight"
placement="bottom-end"
shift
:width="$columnManagerWidth"
:wire:key="$this->getId() . '.table.column-manager'"
class="fi-ta-col-manager-dropdown"
>
<x-slot name="trigger">
{{ $columnManagerTriggerAction }}
</x-slot>
<x-filament-tables::column-manager
:apply-action="$columnManagerApplyAction"
:columns="$columnManagerColumns"
:has-reorderable-columns="$hasReorderableColumns"
:has-toggleable-columns="$hasToggleableColumns"
:heading-tag="$secondLevelHeadingTag"
:reorder-animation-duration="$getReorderAnimationDuration()"
/>
</x-filament::dropdown>
@endif
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_AFTER, scopes: static::class) }}
@endif
</div>
@endif
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_END) }}
</div>
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_AFTER) }}
</div>
@if ($isReordering)
<div
x-cloak
wire:key="{{ $this->getId() }}.table.reorder.indicator"
class="fi-ta-reorder-indicator"
>
{{
\Filament\Support\generate_loading_indicator_html(new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => 'reorderTable',
]))
}}
{{ __('filament-tables::table.reorder_indicator') }}
</div>
@elseif ($isSelectionEnabled && ($maxSelectableRecords !== 1) && $isLoaded)
<div
x-cloak
x-bind:hidden="! getSelectedRecordsCount()"
x-show="getSelectedRecordsCount()"
wire:key="{{ $this->getId() }}.table.selection.indicator"
class="fi-ta-selection-indicator"
>
@if(!$isSelectionDisabled)
<x-filament::link
color="danger"
tag="button"
x-on:click="deselectAllRecords"
x-tooltip="{
content: '{{ __('filament-tables::table.selection_indicator.actions.deselect_all.label') }}',
theme: $store.theme,
}"
class="rounded-full fi-icon-btn"
>
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::XCircle, alias: \Filament\Tables\View\TablesIconAlias::REORDER_HANDLE) }}
</x-filament::link>
@else
@endif
<div>
{{
\Filament\Support\generate_loading_indicator_html(new \Illuminate\View\ComponentAttributeBag([
'x-show' => 'isLoading',
]))
}}
<span class=""
x-text="
window.pluralize(@js(__('filament-tables::table.selection_indicator.selected_count')), getSelectedRecordsCount(), {
count: new Intl.NumberFormat(@js(str_replace('_', '-', app()->getLocale()))).format(getSelectedRecordsCount()),
})
"
></span>
</div>
@if (! $isSelectionDisabled)
<div>
{{ FilamentView::renderHook(TablesRenderHook::SELECTION_INDICATOR_ACTIONS_BEFORE, scopes: static::class) }}
<div class="fi-ta-selection-indicator-actions-ctn">
<x-filament::link
color="primary"
tag="button"
x-on:click="selectAllRecords"
x-show="canSelectAllRecords()"
{{-- Make sure the Alpine attributes get re-evaluated after a Livewire request: --}}
:wire:key="$this->getId() . 'table.selection.indicator.actions.select-all.' . $allSelectableRecordsCount . '.' . $page"
>
{{ trans_choice('filament-tables::table.selection_indicator.actions.select_all.label', $allSelectableRecordsCount, ['count' => \Illuminate\Support\Number::format($allSelectableRecordsCount, locale: app()->getLocale())]) }}
</x-filament::link>
</div>
{{ FilamentView::renderHook(TablesRenderHook::SELECTION_INDICATOR_ACTIONS_AFTER, scopes: static::class) }}
</div>
@endif
<div class="fi-ta-actions fi-align-start fi-wrapped">
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_REORDER_TRIGGER_BEFORE, scopes: static::class) }}
@if ($isReorderable)
{{ $reorderRecordsTriggerAction }}
@endif
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_REORDER_TRIGGER_AFTER, scopes: static::class) }}
@if ((! $isReordering) && count($toolbarActions))
@foreach ($toolbarActions as $action)
{{ $action }}
@endforeach
@endif
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_BEFORE, scopes: static::class) }}
@if ($areGroupingSettingsVisible)
<div
x-data="{
grouping: $wire.$entangle('tableGrouping', true),
group: null,
direction: null,
}"
x-init="
if (grouping) {
;[group, direction] = grouping.split(':')
direction ??= 'asc'
}
$watch('grouping', function () {
if (! grouping) {
group = null
direction = null
return
}
;[group, direction] = grouping.split(':')
direction ??= 'asc'
})
$watch('direction', function () {
grouping = group ? `${group}:${direction}` : null
})
$watch('group', function (newGroup, oldGroup) {
if (! newGroup) {
direction = null
grouping = group ? `${group}:${direction}` : null
return
}
if (oldGroup) {
grouping = group ? `${group}:${direction}` : null
return
}
direction ??= 'asc'
grouping = group ? `${group}:${direction}` : null
})
"
class="fi-ta-grouping-settings"
>
<x-filament::dropdown
placement="bottom-start"
shift
width="xs"
wire:key="{{ $this->getId() }}.table.grouping"
@class([
'sm:fi-hidden' => ! $areGroupingSettingsInDropdownOnDesktop,
])
>
<x-slot name="trigger">
{{ $getGroupRecordsTriggerAction() }}
</x-slot>
<div class="fi-ta-grouping-settings-fields">
<label>
<span>
{{ __('filament-tables::table.grouping.fields.group.label') }}
</span>
<x-filament::input.wrapper>
<x-filament::input.select
x-model="group"
x-on:change="resetCollapsedGroups()"
>
<option value="">-</option>
@foreach ($groups as $groupOption)
<option
value="{{ $groupOption->getId() }}"
>
{{ $groupOption->getLabel() }}
</option>
@endforeach
</x-filament::input.select>
</x-filament::input.wrapper>
</label>
@if (! $isGroupingDirectionSettingHidden)
<label x-cloak x-show="group">
<span>
{{ __('filament-tables::table.grouping.fields.direction.label') }}
</span>
<x-filament::input.wrapper>
<x-filament::input.select
x-model="direction"
>
<option value="asc">
{{ __('filament-tables::table.grouping.fields.direction.options.asc') }}
</option>
<option value="desc">
{{ __('filament-tables::table.grouping.fields.direction.options.desc') }}
</option>
</x-filament::input.select>
</x-filament::input.wrapper>
</label>
@endif
</div>
</x-filament::dropdown>
@if (! $areGroupingSettingsInDropdownOnDesktop)
<div class="fi-ta-grouping-settings-fields">
<label>
<x-filament::input.wrapper
:prefix="__('filament-tables::table.grouping.fields.group.label')"
>
<x-filament::input.select
x-model="group"
x-on:change="resetCollapsedGroups()"
>
<option value="">-</option>
@foreach ($groups as $groupOption)
<option
value="{{ $groupOption->getId() }}"
>
{{ $groupOption->getLabel() }}
</option>
@endforeach
</x-filament::input.select>
</x-filament::input.wrapper>
</label>
@if (! $isGroupingDirectionSettingHidden)
<label x-cloak x-show="group">
<span class="fi-sr-only">
{{ __('filament-tables::table.grouping.fields.direction.label') }}
</span>
<x-filament::input.wrapper>
<x-filament::input.select
x-model="direction"
>
<option value="asc">
{{ __('filament-tables::table.grouping.fields.direction.options.asc') }}
</option>
<option value="desc">
{{ __('filament-tables::table.grouping.fields.direction.options.desc') }}
</option>
</x-filament::input.select>
</x-filament::input.wrapper>
</label>
@endif
</div>
@endif
</div>
@endif
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_AFTER, scopes: static::class) }}
</div>
</div>
@endif
@if ($filterIndicators)
@if (filled($filterIndicatorsView = FilamentView::renderHook(TablesRenderHook::FILTER_INDICATORS, scopes: static::class, data: ['filterIndicators' => $filterIndicators])))
{{ $filterIndicatorsView }}
@else
<div class="fi-ta-filter-indicators">
<div>
<span class="fi-ta-filter-indicators-label">
{{ __('filament-tables::table.filters.indicator') }}
</span>
<div class="fi-ta-filter-indicators-badges-ctn">
@foreach ($filterIndicators as $indicator)
@php
$indicatorColor = $indicator->getColor();
@endphp
<x-filament::badge :color="$indicatorColor">
{{ $indicator->getLabel() }}
@if ($indicator->isRemovable())
@php
$indicatorRemoveLivewireClickHandler = $indicator->getRemoveLivewireClickHandler();
@endphp
<x-slot
name="deleteButton"
:label="__('filament-tables::table.filters.actions.remove.label')"
:wire:click="$indicatorRemoveLivewireClickHandler"
wire:loading.attr="disabled"
wire:target="removeTableFilter"
></x-slot>
@endif
</x-filament::badge>
@endforeach
</div>
</div>
@if (collect($filterIndicators)->contains(fn (\Filament\Tables\Filters\Indicator $indicator): bool => $indicator->isRemovable()))
<button
type="button"
x-tooltip="{
content: @js(__('filament-tables::table.filters.actions.remove_all.tooltip')),
theme: $store.theme,
}"
wire:click="removeTableFilters"
wire:loading.attr="disabled"
wire:target="removeTableFilters,removeTableFilter"
class="fi-icon-btn fi-size-sm"
>
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::XMark, alias: \Filament\Tables\View\TablesIconAlias::FILTERS_REMOVE_ALL_BUTTON, size: \Filament\Support\Enums\IconSize::Small) }}
</button>
@endif
</div>
@endif
@endif
@if (((! $content) && (! $hasColumnsLayout)) || ($records === null) || count($records))
<div
@if ((! $isReordering) && ($pollingInterval = $getPollingInterval()))
wire:poll.{{ $pollingInterval }}
@endif
class="fi-ta-content-ctn"
>
@if (($content || $hasColumnsLayout) && ($records !== null) && count($records))
@if (! $isReordering)
@php
$sortableColumns = array_filter(
$columns,
fn (\Filament\Tables\Columns\Column $column): bool => $column->isSortable(),
);
@endphp
@if ($isSelectionEnabled || count($sortableColumns))
<div class="fi-ta-content-header">
@if ($isSelectionEnabled && ($maxSelectableRecords !== 1) && (! $isReordering))
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_page.label') }}"
type="checkbox"
@if ($isSelectionDisabled)
disabled
@elseif ($maxSelectableRecords)
x-bind:disabled="
const recordsOnPage = getRecordsOnPage()
return recordsOnPage.length && ! areRecordsToggleable(recordsOnPage)
"
@endif
x-bind:checked="
const recordsOnPage = getRecordsOnPage()
if (recordsOnPage.length && areRecordsSelected(recordsOnPage)) {
$el.checked = true
return 'checked'
}
$el.checked = false
return null
"
x-on:click="toggleSelectRecordsOnPage"
{{-- Make sure the "checked" state gets re-evaluated after a Livewire request: --}}
wire:key="{{ $this->getId() }}.table.bulk-select-page.checkbox.{{ \Illuminate\Support\Str::random() }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-page-checkbox fi-checkbox-input"
/>
@endif
@if (count($sortableColumns))
<div
x-data="{
sort: $wire.$entangle('tableSort', true),
column: null,
direction: null,
}"
x-init="
if (sort) {
;[column, direction] = sort.split(':')
direction ??= 'asc'
}
$watch('sort', function () {
if (! sort) {
return
}
;[column, direction] = sort.split(':')
direction ??= 'asc'
})
$watch('direction', function () {
sort = column ? `${column}:${direction}` : null
})
$watch('column', function (newColumn, oldColumn) {
if (! newColumn) {
direction = null
sort = column ? `${column}:${direction}` : null
return
}
if (oldColumn) {
sort = column ? `${column}:${direction}` : null
return
}
direction = 'asc'
sort = column ? `${column}:${direction}` : null
})
"
class="fi-ta-sorting-settings"
>
<label>
<x-filament::input.wrapper
:prefix="__('filament-tables::table.sorting.fields.column.label')"
>
<x-filament::input.select
x-model="column"
>
<option value="">
{{ $defaultSortOptionLabel }}
</option>
@foreach ($sortableColumns as $column)
<option
value="{{ $column->getName() }}"
>
{{ $column->getLabel() }}
</option>
@endforeach
</x-filament::input.select>
</x-filament::input.wrapper>
</label>
<label x-cloak x-show="column">
<span class="fi-sr-only">
{{ __('filament-tables::table.sorting.fields.direction.label') }}
</span>
<x-filament::input.wrapper>
<x-filament::input.select
x-model="direction"
>
<option value="asc">
{{ __('filament-tables::table.sorting.fields.direction.options.asc') }}
</option>
<option value="desc">
{{ __('filament-tables::table.sorting.fields.direction.options.desc') }}
</option>
</x-filament::input.select>
</x-filament::input.wrapper>
</label>
</div>
@endif
</div>
@endif
@endif
@if ($content)
{{ $content->with(['records' => $records]) }}
@else
<div
@if ($isReorderable)
x-on:end.stop="
$wire.reorderTable(
$event.target.sortable.toArray(),
$event.item.getAttribute('x-sortable-item'),
)
"
x-sortable
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}"
@endif
{{
(new ComponentAttributeBag)
->when($contentGrid, fn (ComponentAttributeBag $attributes) => $attributes->grid($contentGrid))
->class([
'fi-ta-content',
'fi-ta-content-grid' => $contentGrid,
'fi-ta-content-grouped' => $this->getTableGrouping(),
])
}}
>
@php
$previousRecord = null;
$previousRecordGroupKey = null;
$previousRecordGroupTitle = null;
@endphp
@foreach ($records as $record)
@php
$recordAction = $getRecordAction($record);
$recordKey = $getRecordKey($record);
$recordUrl = $getRecordUrl($record);
$openRecordUrlInNewTab = $shouldOpenRecordUrlInNewTab($record);
$recordGroupKey = $group?->getStringKey($record);
$recordGroupTitle = $group?->getTitle($record);
$isRecordGroupCollapsible = $group?->isCollapsible();
$collapsibleColumnsLayout?->record($record)->recordKey($recordKey);
$hasCollapsibleColumnsLayout = (bool) $collapsibleColumnsLayout?->isVisible();
$recordActions = array_reduce(
$defaultRecordActions,
function (array $carry, $action) use ($record): array {
$action = $action->getClone();
if (! $action instanceof \Filament\Actions\BulkAction) {
$action->record($record);
}
if ($action->isHidden()) {
return $carry;
}
$carry[] = $action;
return $carry;
},
initial: [],
);
@endphp
@if ($recordGroupTitle !== $previousRecordGroupTitle)
@if ($hasSummary && (! $isReordering) && filled($previousRecordGroupTitle))
<table
@class([
'fi-ta-table',
'fi-ta-table-reordering' => $isReordering,
])
>
<tbody>
@php
$groupScopedAllTableSummaryQuery = $group->scopeQuery($this->getAllTableSummaryQuery(), $previousRecord);
@endphp
<x-filament-tables::summary.row
:columns="$columns"
extra-heading-column
:heading="
__('filament-tables::table.summary.subheadings.group', [
'group' => $previousRecordGroupTitle,
'label' => $pluralModelLabel,
])
"
:placeholder-columns="false"
:query="$groupScopedAllTableSummaryQuery"
:selected-state="$groupedSummarySelectedState[$previousRecordGroupKey] ?? []"
/>
</tbody>
</table>
@endif
<div
@if ($isRecordGroupCollapsible = $group->isCollapsible())
x-on:click="toggleCollapseGroup(@js($recordGroupTitle))"
@if (! $hasSummary)
x-bind:class="{ 'fi-collapsed': isGroupCollapsed(@js($recordGroupTitle)) }"
@endif
@endif
@class([
'fi-ta-group-header',
'fi-collapsible' => $isRecordGroupCollapsible,
])
>
@if ($isSelectionEnabled && ($maxSelectableRecords !== 1))
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_group.label', ['title' => $recordGroupTitle]) }}"
type="checkbox"
data-group-selectable-record-keys="{{ json_encode($this->getGroupedSelectableTableRecordKeys($recordGroupKey)) }}"
@if ($isSelectionDisabled)
disabled
@else
x-on:click="toggleSelectRecords(JSON.parse($el.dataset.groupSelectableRecordKeys))"
@if ($maxSelectableRecords)
x-bind:disabled="
const recordsInGroup = JSON.parse($el.dataset.groupSelectableRecordKeys)
return recordsInGroup.length && ! areRecordsToggleable(recordsInGroup)
"
@endif
@endif
x-bind:checked="
const recordsInGroup = JSON.parse($el.dataset.groupSelectableRecordKeys)
if (recordsInGroup.length && areRecordsSelected(recordsInGroup)) {
$el.checked = true
return 'checked'
}
$el.checked = false
return null
"
wire:key="{{ $this->getId() }}.table.bulk_select_group.checkbox.{{ $page }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-group-checkbox fi-checkbox-input"
/>
@endif
<div>
<{{ $secondLevelHeadingTag }}
class
="fi-ta-group-heading"
>
@if (filled($recordGroupLabel = ($group->isTitlePrefixedWithLabel() ? $group->getLabel() : null)))
{{ $recordGroupLabel }}:
@endif
{{ $recordGroupTitle }}
</{{ $secondLevelHeadingTag }}>
@if (filled($recordGroupDescription = $group->getDescription($record, $recordGroupTitle)))
<p
class="fi-ta-group-description"
>
{{ $recordGroupDescription }}
</p>
@endif
</div>
@if ($isRecordGroupCollapsible)
<button
aria-label="{{ filled($recordGroupLabel) ? ($recordGroupLabel . ': ' . $recordGroupTitle) : $recordGroupTitle }}"
x-bind:aria-expanded="! isGroupCollapsed(@js($recordGroupTitle))"
type="button"
class="fi-icon-btn fi-size-sm"
>
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::ChevronUp, alias: \Filament\Tables\View\TablesIconAlias::GROUPING_COLLAPSE_BUTTON, size: \Filament\Support\Enums\IconSize::Small) }}
</button>
@endif
</div>
@endif
<div
@if ($hasCollapsibleColumnsLayout)
x-data="{ isCollapsed: @js($collapsibleColumnsLayout->isCollapsed()) }"
x-init="$dispatch('collapsible-table-row-initialized')"
x-on:collapse-all-table-rows.window="isCollapsed = true"
x-on:expand-all-table-rows.window="isCollapsed = false"
x-bind:class="isCollapsed && 'fi-ta-record-collapsed'"
@endif
wire:key="{{ $this->getId() }}.table.records.{{ $recordKey }}"
@if ($isReordering)
x-sortable-item="{{ $recordKey }}"
x-sortable-handle
@endif
@class([
'fi-ta-record',
'fi-clickable' => $recordUrl || $recordAction,
'fi-ta-record-with-content-prefix' => $isReordering || ($isSelectionEnabled && $isRecordSelectable($record)),
'fi-ta-record-with-content-suffix' => $hasCollapsibleColumnsLayout && (! $isReordering),
...$getRecordClasses($record),
])
x-bind:class="{
{{ $group?->isCollapsible() ? '\'fi-collapsed\': isGroupCollapsed(' . \Illuminate\Support\Js::from($recordGroupTitle) . '),' : '' }}
'fi-selected': isRecordSelected(@js($recordKey)),
}"
>
@php
$hasItemBeforeRecordContent = $isReordering || ($isSelectionEnabled && $isRecordSelectable($record));
$hasItemAfterRecordContent = $hasCollapsibleColumnsLayout && (! $isReordering);
@endphp
@if ($isReordering)
<button
class="fi-ta-reorder-handle fi-icon-btn"
type="button"
>
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::Bars2, alias: \Filament\Tables\View\TablesIconAlias::REORDER_HANDLE) }}
</button>
@elseif ($isSelectionEnabled && $isRecordSelectable($record))
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_record.label', ['key' => $recordKey]) }}"
type="checkbox"
@if ($isSelectionDisabled)
disabled
@elseif ($maxSelectableRecords && ($maxSelectableRecords !== 1))
x-bind:disabled="! areRecordsToggleable([@js($recordKey)])"
@endif
value="{{ $recordKey }}"
x-on:click="toggleSelectedRecord(@js($recordKey))"
x-bind:checked="isRecordSelected(@js($recordKey)) ? 'checked' : null"
data-group="{{ $recordGroupKey }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-record-checkbox fi-checkbox-input"
/>
@endif
<div class="fi-ta-record-content-ctn">
<div>
@if ($recordUrl)
<a
{{ \Filament\Support\generate_href_html($recordUrl, $openRecordUrlInNewTab) }}
class="fi-ta-record-content"
>
@foreach ($columnsLayout as $columnsLayoutComponent)
{{
$columnsLayoutComponent
->record($record)
->recordKey($recordKey)
->rowLoop($loop)
->renderInLayout()
}}
@endforeach
</a>
@elseif ($recordAction)
@php
$recordWireClickAction = $getRecordAction($record)
? "mountTableAction('{$recordAction}', '{$recordKey}')"
: $recordWireClickAction = "{$recordAction}('{$recordKey}')";
@endphp
<button
type="button"
wire:click="{{ $recordWireClickAction }}"
wire:loading.attr="disabled"
wire:target="{{ $recordWireClickAction }}"
class="fi-ta-record-content"
>
@foreach ($columnsLayout as $columnsLayoutComponent)
{{
$columnsLayoutComponent
->record($record)
->recordKey($recordKey)
->rowLoop($loop)
->renderInLayout()
}}
@endforeach
</button>
@else
<div
class="fi-ta-record-content"
>
@foreach ($columnsLayout as $columnsLayoutComponent)
{{
$columnsLayoutComponent
->record($record)
->recordKey($recordKey)
->rowLoop($loop)
->renderInLayout()
}}
@endforeach
</div>
@endif
@if ($hasCollapsibleColumnsLayout && (! $isReordering))
<div
x-collapse
x-show="! isCollapsed"
class="fi-ta-record-content fi-collapsible"
>
{{ $collapsibleColumnsLayout }}
</div>
@endif
</div>
@if ($recordActions && (! $isReordering))
<div
@class([
'fi-ta-actions fi-wrapped sm:fi-not-wrapped',
match ($recordActionsAlignment ?? Alignment::Start) {
Alignment::Start => 'fi-align-start',
Alignment::Center => 'fi-align-center',
Alignment::End => 'fi-align-end',
} => $contentGrid,
'fi-align-start md:fi-align-end' => ! $contentGrid,
'fi-ta-actions-before-columns-position' => $recordActionsPosition === RecordActionsPosition::BeforeColumns,
])
>
@foreach ($recordActions as $action)
{{ $action }}
@endforeach
</div>
@endif
</div>
@if ($hasCollapsibleColumnsLayout && (! $isReordering))
<button
type="button"
x-on:click="isCollapsed = ! isCollapsed"
class="fi-ta-record-collapse-btn fi-icon-btn"
>
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::ChevronDown, alias: \Filament\Tables\View\TablesIconAlias::COLUMNS_COLLAPSE_BUTTON) }}
</button>
@endif
</div>
@php
$previousRecordGroupKey = $recordGroupKey;
$previousRecordGroupTitle = $recordGroupTitle;
$previousRecord = $record;
@endphp
@endforeach
@if ($hasSummary && (! $isReordering) && filled($previousRecordGroupTitle) && ((! $records instanceof \Illuminate\Contracts\Pagination\Paginator) || (! $records->hasMorePages())))
<table class="fi-ta-table">
<tbody>
@php
$groupScopedAllTableSummaryQuery = $group->scopeQuery($this->getAllTableSummaryQuery(), $previousRecord);
@endphp
<x-filament-tables::summary.row
:columns="$columns"
extra-heading-column
:heading="__('filament-tables::table.summary.subheadings.group', ['group' => $previousRecordGroupTitle, 'label' => $pluralModelLabel])"
:placeholder-columns="false"
:query="$groupScopedAllTableSummaryQuery"
:selected-state="$groupedSummarySelectedState[$previousRecordGroupKey] ?? []"
/>
</tbody>
</table>
@endif
</div>
@endif
@if (($content || $hasColumnsLayout) && $contentFooter)
{{
$contentFooter->with([
'columns' => $columns,
'records' => $records,
])
}}
@endif
@if ($hasSummary && (! $isReordering))
<table class="fi-ta-table">
<tbody>
<x-filament-tables::summary
:columns="$columns"
extra-heading-column
:placeholder-columns="false"
:plural-model-label="$pluralModelLabel"
:records="$records"
/>
</tbody>
</table>
@endif
@elseif ((! ($content || $hasColumnsLayout)) && ($records !== null))
<table class="fi-ta-table">
<thead>
@if ($hasColumnGroups)
<tr class="fi-ta-table-head-groups-row">
@if (count($records))
@if ($isReordering)
<th></th>
@else
@if (count($defaultRecordActions) && in_array($recordActionsPosition, [RecordActionsPosition::BeforeCells, RecordActionsPosition::BeforeColumns]))
<th></th>
@endif
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::BeforeCells)
<th></th>
@endif
@endif
@endif
@foreach ($columnsLayout as $columnGroup)
@if ($columnGroup instanceof Column)
@if ($columnGroup->isVisible() && (! $columnGroup->isToggledHidden()))
<th></th>
@endif
@elseif ($columnGroup instanceof ColumnGroup)
@php
$columnGroupColumnsCount = count($columnGroup->getVisibleColumns());
@endphp
@if ($columnGroupColumnsCount)
<th
colspan="{{ $columnGroupColumnsCount }}"
{{
$columnGroup->getExtraHeaderAttributeBag()->class([
'fi-ta-header-group-cell',
'fi-wrapped' => $columnGroup->canHeaderWrap(),
((($columnGroupAlignment = $columnGroup->getAlignment()) instanceof \Filament\Support\Enums\Alignment) ? "fi-align-{$columnGroupAlignment->value}" : (is_string($columnGroupAlignment) ? $columnGroupAlignment : '')),
(filled($columnGroupHiddenFrom = $columnGroup->getHiddenFrom()) ? "{$columnGroupHiddenFrom}:fi-hidden" : ''),
(filled($columnGroupVisibleFrom = $columnGroup->getVisibleFrom()) ? "{$columnGroupVisibleFrom}:fi-visible" : ''),
])
}}
>
{{ $columnGroup->getLabel() }}
</th>
@endif
@endif
@endforeach
@if ((! $isReordering) && count($records))
@if (count($defaultRecordActions) && in_array($recordActionsPosition, [RecordActionsPosition::AfterColumns, RecordActionsPosition::AfterCells]))
<th></th>
@endif
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::AfterCells)
<th></th>
@endif
@endif
</tr>
@endif
<tr>
@if (count($records))
@if ($isReordering)
<th></th>
@else
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::BeforeCells)
@if ($recordActionsColumnLabel)
<th class="fi-ta-header-cell">
{{ $recordActionsColumnLabel }}
</th>
@else
<th
aria-label="{{ trans_choice('filament-tables::table.columns.actions.label', $flatRecordActionsCount) }}"
class="fi-ta-actions-header-cell fi-ta-empty-header-cell"
></th>
@endif
@endif
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::BeforeCells)
<th
class="fi-ta-cell fi-ta-selection-cell"
>
@if ($maxSelectableRecords !== 1)
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_page.label') }}"
type="checkbox"
@if ($isSelectionDisabled)
disabled
@elseif ($maxSelectableRecords)
x-bind:disabled="
const recordsOnPage = getRecordsOnPage()
return recordsOnPage.length && ! areRecordsToggleable(recordsOnPage)
"
@endif
x-bind:checked="
const recordsOnPage = getRecordsOnPage()
if (recordsOnPage.length && areRecordsSelected(recordsOnPage)) {
$el.checked = true
return 'checked'
}
$el.checked = false
return null
"
x-on:click="toggleSelectRecordsOnPage"
{{-- Make sure the "checked" state gets re-evaluated after a Livewire request: --}}
wire:key="{{ $this->getId() }}.table.bulk-select-page.checkbox.{{ \Illuminate\Support\Str::random() }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-page-checkbox fi-checkbox-input"
/>
@endif
</th>
@endif
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::BeforeColumns)
@if ($recordActionsColumnLabel)
<th class="fi-ta-header-cell">
{{ $recordActionsColumnLabel }}
</th>
@else
<th
aria-label="{{ trans_choice('filament-tables::table.columns.actions.label', $flatRecordActionsCount) }}"
class="fi-ta-actions-header-cell fi-ta-empty-header-cell"
></th>
@endif
@endif
@endif
@endif
@foreach ($columns as $column)
@php
$columnName = $column->getName();
$columnLabel = $column->getLabel();
$columnAlignment = $column->getAlignment();
$columnWidth = $column->getWidth();
$isColumnActivelySorted = $getSortColumn() === $column->getName();
$isColumnSortable = $column->isSortable() && (! $isReordering);
@endphp
<th
@if ($isColumnActivelySorted)
aria-sort="{{ $sortDirection === 'asc' ? 'ascending' : 'descending' }}"
@endif
{{
$column->getExtraHeaderAttributeBag()
->class([
'fi-ta-header-cell',
'fi-ta-header-cell-' . str($columnName)->camel()->kebab(),
'fi-growable' => blank($columnWidth) && $column->canGrow(default: false),
'fi-grouped' => $column->getGroup(),
'fi-wrapped' => $column->canHeaderWrap(),
'fi-ta-header-cell-sorted' => $isColumnActivelySorted,
((($columnAlignment = $column->getAlignment()) instanceof \Filament\Support\Enums\Alignment) ? "fi-align-{$columnAlignment->value}" : (is_string($columnAlignment) ? $columnAlignment : '')),
(filled($columnHiddenFrom = $column->getHiddenFrom()) ? "{$columnHiddenFrom}:fi-hidden" : ''),
(filled($columnVisibleFrom = $column->getVisibleFrom()) ? "{$columnVisibleFrom}:fi-visible" : ''),
])
->style([
('width: ' . $columnWidth) => filled($columnWidth),
])
}}
>
@if ($isColumnSortable)
<span
aria-label="{{ trim(strip_tags($columnLabel)) }}"
role="button"
tabindex="0"
wire:click="sortTable('{{ $columnName }}')"
x-on:keydown.enter.prevent.stop="$wire.sortTable('{{ $columnName }}')"
x-on:keydown.space.prevent.stop="$wire.sortTable('{{ $columnName }}')"
wire:loading.attr="disabled"
class="fi-ta-header-cell-sort-btn"
>
{{ $columnLabel }}
{{
\Filament\Support\generate_icon_html(($isColumnActivelySorted && $sortDirection === 'asc') ? \Filament\Support\Icons\Heroicon::ChevronUp : \Filament\Support\Icons\Heroicon::ChevronDown, alias: match (true) {
$isColumnActivelySorted && ($sortDirection === 'asc') => \Filament\Tables\View\TablesIconAlias::HEADER_CELL_SORT_ASC_BUTTON,
$isColumnActivelySorted && ($sortDirection === 'desc') => \Filament\Tables\View\TablesIconAlias::HEADER_CELL_SORT_DESC_BUTTON,
default => \Filament\Tables\View\TablesIconAlias::HEADER_CELL_SORT_BUTTON,
})
}}
</span>
@else
{{ $columnLabel }}
@endif
</th>
@endforeach
@if ((! $isReordering) && count($records))
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::AfterColumns)
@if ($recordActionsColumnLabel)
<th
class="fi-ta-header-cell fi-align-end"
>
{{ $recordActionsColumnLabel }}
</th>
@else
<th
aria-label="{{ trans_choice('filament-tables::table.columns.actions.label', $flatRecordActionsCount) }}"
class="fi-ta-actions-header-cell fi-ta-empty-header-cell"
></th>
@endif
@endif
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::AfterCells)
<th
class="fi-ta-cell fi-ta-selection-cell"
>
@if ($maxSelectableRecords !== 1)
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_page.label') }}"
type="checkbox"
@if ($isSelectionDisabled)
disabled
@elseif ($maxSelectableRecords)
x-bind:disabled="
const recordsOnPage = getRecordsOnPage()
return recordsOnPage.length && ! areRecordsToggleable(recordsOnPage)
"
@endif
x-bind:checked="
const recordsOnPage = getRecordsOnPage()
if (recordsOnPage.length && areRecordsSelected(recordsOnPage)) {
$el.checked = true
return 'checked'
}
$el.checked = false
return null
"
x-on:click="toggleSelectRecordsOnPage"
{{-- Make sure the "checked" state gets re-evaluated after a Livewire request: --}}
wire:key="{{ $this->getId() }}.table.bulk-select-page.checkbox.{{ \Illuminate\Support\Str::random() }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-page-checkbox fi-checkbox-input"
/>
@endif
</th>
@endif
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::AfterCells)
@if ($recordActionsColumnLabel)
<th
class="fi-ta-header-cell fi-align-end"
>
{{ $recordActionsColumnLabel }}
</th>
@else
<th
aria-label="{{ trans_choice('filament-tables::table.columns.actions.label', $flatRecordActionsCount) }}"
class="fi-ta-actions-header-cell fi-ta-empty-header-cell"
></th>
@endif
@endif
@endif
</tr>
</thead>
@if ($isColumnSearchVisible || count($records))
<tbody
@if ($isReorderable)
x-on:end.stop="
$wire.reorderTable(
$event.target.sortable.toArray(),
$event.item.getAttribute('x-sortable-item'),
)
"
x-sortable
data-sortable-animation-duration="{{ $getReorderAnimationDuration() }}"
@endif
>
@if ($isColumnSearchVisible)
<tr
class="fi-ta-row fi-ta-row-not-reorderable"
>
@if (count($records))
@if ($isReordering)
<td></td>
@else
@if (count($defaultRecordActions) && in_array($recordActionsPosition, [RecordActionsPosition::BeforeCells, RecordActionsPosition::BeforeColumns]))
<td></td>
@endif
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::BeforeCells)
<td></td>
@endif
@endif
@endif
@foreach ($columns as $column)
@php
$columnName = $column->getName();
@endphp
<td
@class([
'fi-ta-cell',
'fi-ta-individual-search-cell' => $isIndividuallySearchable = $column->isIndividuallySearchable(),
'fi-ta-individual-search-cell-' . str($columnName)->camel()->kebab() => $isIndividuallySearchable,
])
>
@if ($isIndividuallySearchable)
<x-filament-tables::search-field
:debounce="$searchDebounce"
:on-blur="$isSearchOnBlur"
:wire-model="'tableColumnSearches.' . $columnName"
/>
@endif
</td>
@endforeach
@if ((! $isReordering) && count($records))
@if (count($defaultRecordActions) && in_array($recordActionsPosition, [RecordActionsPosition::AfterColumns, RecordActionsPosition::AfterCells]))
<td></td>
@endif
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::AfterCells)
<td></td>
@endif
@endif
</tr>
@endif
@if (count($records))
@php
$isRecordRowStriped = false;
$previousRecord = null;
$previousRecordGroupKey = null;
$previousRecordGroupTitle = null;
@endphp
@foreach ($records as $record)
@php
$recordAction = $getRecordAction($record);
$recordKey = $getRecordKey($record);
$recordUrl = $getRecordUrl($record);
$openRecordUrlInNewTab = $shouldOpenRecordUrlInNewTab($record);
$recordGroupKey = $group?->getStringKey($record);
$recordGroupTitle = $group?->getTitle($record);
$recordActions = array_reduce(
$defaultRecordActions,
function (array $carry, $action) use ($record): array {
$action = $action->getClone();
if (! $action instanceof \Filament\Actions\BulkAction) {
$action->record($record);
}
if ($action->isHidden()) {
return $carry;
}
$carry[] = $action;
return $carry;
},
initial: [],
);
@endphp
@if ($recordGroupTitle !== $previousRecordGroupTitle)
@if ($hasSummary && (! $isReordering) && filled($previousRecordGroupTitle))
@php
$groupColumn = $group->getColumn();
$groupScopedAllTableSummaryQuery = $group->scopeQuery($this->getAllTableSummaryQuery(), $previousRecord);
@endphp
<x-filament-tables::summary.row
:actions="count($defaultRecordActions)"
:actions-position="$recordActionsPosition"
:columns="$columns"
:group-column="$groupColumn"
:groups-only="$isGroupsOnly"
:heading="$isGroupsOnly ? $previousRecordGroupTitle : __('filament-tables::table.summary.subheadings.group', ['group' => $previousRecordGroupTitle, 'label' => $pluralModelLabel])"
:query="$groupScopedAllTableSummaryQuery"
:record-checkbox-position="$recordCheckboxPosition"
:selected-state="$groupedSummarySelectedState[$previousRecordGroupKey] ?? []"
:selection-enabled="$isSelectionEnabled"
/>
@endif
@if (! $isGroupsOnly)
<tr
class="fi-ta-row fi-ta-group-header-row"
>
@php
$isRecordGroupCollapsible = $group?->isCollapsible();
$groupHeaderColspan = $columnsCount;
if ($isSelectionEnabled) {
$groupHeaderColspan--;
if (
($recordCheckboxPosition === RecordCheckboxPosition::BeforeCells) &&
count($defaultRecordActions) &&
($recordActionsPosition === RecordActionsPosition::BeforeCells)
) {
$groupHeaderColspan--;
}
}
@endphp
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::BeforeCells)
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::BeforeCells)
<td></td>
@endif
<td
class="fi-ta-cell fi-ta-group-selection-cell"
>
@if ($maxSelectableRecords !== 1)
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_group.label', ['title' => $recordGroupTitle]) }}"
type="checkbox"
data-group-selectable-record-keys="{{ json_encode($this->getGroupedSelectableTableRecordKeys($recordGroupKey)) }}"
@if ($isSelectionDisabled)
disabled
@else
x-on:click="toggleSelectRecords(JSON.parse($el.dataset.groupSelectableRecordKeys))"
@if ($maxSelectableRecords)
x-bind:disabled="
const recordsInGroup = JSON.parse($el.dataset.groupSelectableRecordKeys)
return recordsInGroup.length && ! areRecordsToggleable(recordsInGroup)
"
@endif
@endif
x-bind:checked="
const recordsInGroup = JSON.parse($el.dataset.groupSelectableRecordKeys)
if (recordsInGroup.length && areRecordsSelected(recordsInGroup)) {
$el.checked = true
return 'checked'
}
$el.checked = false
return null
"
wire:key="{{ $this->getId() }}.table.bulk_select_group.checkbox.{{ $page }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-group-checkbox fi-checkbox-input"
/>
@endif
</td>
@endif
<td
colspan="{{ $groupHeaderColspan }}"
class="fi-ta-group-header-cell"
>
<div
@if ($isRecordGroupCollapsible)
x-on:click="toggleCollapseGroup(@js($recordGroupTitle))"
x-bind:class="isGroupCollapsed(@js($recordGroupTitle)) ? 'fi-collapsed' : null"
@endif
@class([
'fi-ta-group-header',
'fi-collapsible' => $isRecordGroupCollapsible,
])
>
<div>
<{{ $secondLevelHeadingTag }}
class
="fi-ta-group-heading"
>
@if (filled($recordGroupLabel = ($group->isTitlePrefixedWithLabel() ? $group->getLabel() : null)))
{{ $recordGroupLabel }}:
@endif
{{ $recordGroupTitle }}
</{{ $secondLevelHeadingTag }}>
@if (filled($recordGroupDescription = $group->getDescription($record, $recordGroupTitle)))
<p
class="fi-ta-group-description"
>
{{ $recordGroupDescription }}
</p>
@endif
</div>
@if ($isRecordGroupCollapsible)
<button
aria-label="{{ filled($recordGroupLabel) ? ($recordGroupLabel . ': ' . $recordGroupTitle) : $recordGroupTitle }}"
x-bind:aria-expanded="! isGroupCollapsed(@js($recordGroupTitle))"
type="button"
class="fi-icon-btn fi-size-sm"
>
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::ChevronUp, alias: \Filament\Tables\View\TablesIconAlias::GROUPING_COLLAPSE_BUTTON, size: \Filament\Support\Enums\IconSize::Small) }}
</button>
@endif
</div>
</td>
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::AfterCells)
<td
class="fi-ta-cell fi-ta-group-selection-cell"
>
@if ($maxSelectableRecords !== 1)
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_group.label', ['title' => $recordGroupTitle]) }}"
type="checkbox"
data-group-selectable-record-keys="{{ json_encode($this->getGroupedSelectableTableRecordKeys($recordGroupKey)) }}"
@if ($isSelectionDisabled)
disabled
@else
x-on:click="toggleSelectRecords(JSON.parse($el.dataset.groupSelectableRecordKeys))"
@if ($maxSelectableRecords)
x-bind:disabled="
const recordsInGroup = JSON.parse($el.dataset.groupSelectableRecordKeys)
return recordsInGroup.length && ! areRecordsToggleable(recordsInGroup)
"
@endif
@endif
x-bind:checked="
const recordsInGroup = JSON.parse($el.dataset.groupSelectableRecordKeys)
if (recordsInGroup.length && areRecordsSelected(recordsInGroup)) {
$el.checked = true
return 'checked'
}
$el.checked = false
return null
"
wire:key="{{ $this->getId() }}.table.bulk_select_group.checkbox.{{ $page }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-group-checkbox fi-checkbox-input"
/>
@endif
</td>
@endif
</tr>
@endif
@php
$isRecordRowStriped = false;
@endphp
@endif
@if (! $isGroupsOnly)
<tr
wire:key="{{ $this->getId() }}.table.records.{{ $recordKey }}"
{{ $isReordering ? 'x-sortable-handle' : null }}
{!! $isReordering ? 'x-sortable-item="' . e($recordKey) . '"' : null !!}
x-bind:class="{
{{ $group?->isCollapsible() ? '\'fi-collapsed\': isGroupCollapsed(' . \Illuminate\Support\Js::from($recordGroupTitle) . '),' : '' }}
'fi-selected': isRecordSelected(@js($recordKey)),
}"
@class([
'fi-ta-row',
'fi-clickable' => $recordAction || $recordUrl,
'fi-striped' => $isStriped && $isRecordRowStriped,
...$getRecordClasses($record),
])
>
@if ($isReordering)
<td class="fi-ta-cell">
<button
class="fi-ta-reorder-handle fi-icon-btn"
type="button"
>
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::Bars2, alias: \Filament\Tables\View\TablesIconAlias::REORDER_HANDLE) }}
</button>
</td>
@endif
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::BeforeCells && (! $isReordering))
<td class="fi-ta-cell">
<div
@class([
'fi-ta-actions',
match ($recordActionsAlignment) {
Alignment::Center => 'fi-align-center',
Alignment::Start, Alignment::Left => 'fi-align-start',
Alignment::Between, Alignment::Justify => 'fi-align-between',
Alignment::End, Alignment::Right => '',
default => is_string($recordActionsAlignment) ? $recordActionsAlignment : '',
},
])
>
@foreach ($recordActions as $action)
{{ $action }}
@endforeach
</div>
</td>
@endif
@if ($isSelectionEnabled && ($recordCheckboxPosition === RecordCheckboxPosition::BeforeCells) && (! $isReordering))
<td
class="fi-ta-cell fi-ta-selection-cell"
>
@if ($isRecordSelectable($record))
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_record.label', ['key' => $recordKey]) }}"
type="checkbox"
@if ($isSelectionDisabled)
disabled
@elseif ($maxSelectableRecords && ($maxSelectableRecords !== 1))
x-bind:disabled="! areRecordsToggleable([@js($recordKey)])"
@endif
value="{{ $recordKey }}"
x-on:click="toggleSelectedRecord(@js($recordKey))"
x-bind:checked="isRecordSelected(@js($recordKey)) ? 'checked' : null"
data-group="{{ $recordGroupKey }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-record-checkbox fi-checkbox-input"
/>
@endif
</td>
@endif
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::BeforeColumns && (! $isReordering))
<td class="fi-ta-cell">
<div
@class([
'fi-ta-actions',
match ($recordActionsAlignment) {
Alignment::Center => 'fi-align-center',
Alignment::Start, Alignment::Left => 'fi-align-start',
Alignment::Between, Alignment::Justify => 'fi-align-between',
Alignment::End, Alignment::Right => '',
default => is_string($recordActionsAlignment) ? $recordActionsAlignment : '',
},
])
>
@foreach ($recordActions as $action)
{{ $action }}
@endforeach
</div>
</td>
@endif
@foreach ($columns as $column)
@php
$column->record($record);
$column->rowLoop($loop->parent);
$column->recordKey($recordKey);
$columnAction = $column->getAction();
$columnUrl = $column->getUrl();
$columnHasStateBasedUrls = $column->hasStateBasedUrls();
$isColumnClickDisabled = $column->isClickDisabled() || $isReordering;
$columnWrapperTag = match (true) {
($columnUrl || ($recordUrl && $columnAction === null)) && (! $columnHasStateBasedUrls) && (! $isColumnClickDisabled) => 'a',
($columnAction || $recordAction) && (! $columnHasStateBasedUrls) && (! $isColumnClickDisabled) => 'button',
default => 'div',
};
if ($columnWrapperTag === 'button') {
if ($columnAction instanceof \Filament\Actions\Action) {
$columnWireClickAction = "mountTableAction('{$columnAction->getName()}', '{$recordKey}')";
} elseif ($columnAction) {
$columnWireClickAction = "callTableColumnAction('{$column->getName()}', '{$recordKey}')";
} else {
if ($this->getTable()->getAction($recordAction)) {
$columnWireClickAction = "mountTableAction('{$recordAction}', '{$recordKey}')";
} else {
$columnWireClickAction = "{$recordAction}('{$recordKey}')";
}
}
}
@endphp
<td
wire:key="{{ $this->getId() }}.table.record.{{ $recordKey }}.column.{{ $column->getName() }}"
{{
$column->getExtraCellAttributeBag()->class([
'fi-ta-cell',
'fi-ta-cell-' . str($column->getName())->camel()->kebab(),
((($columnAlignment = $column->getAlignment()) instanceof \Filament\Support\Enums\Alignment) ? "fi-align-{$columnAlignment->value}" : (is_string($columnAlignment) ? $columnAlignment : '')),
((($columnVerticalAlignment = $column->getVerticalAlignment()) instanceof \Filament\Support\Enums\VerticalAlignment) ? "fi-vertical-align-{$columnVerticalAlignment->value}" : (is_string($columnVerticalAlignment) ? $columnVerticalAlignment : '')),
(filled($columnHiddenFrom = $column->getHiddenFrom()) ? "{$columnHiddenFrom}:fi-hidden" : ''),
(filled($columnVisibleFrom = $column->getVisibleFrom()) ? "{$columnVisibleFrom}:fi-visible" : ''),
])
}}
>
<{{ $columnWrapperTag }}
@if ($columnWrapperTag === 'a')
{{ \Filament\Support\generate_href_html($columnUrl ?: $recordUrl, $columnUrl ? $column->shouldOpenUrlInNewTab() : $openRecordUrlInNewTab) }}
@elseif ($columnWrapperTag === 'button')
type
="button"
wire:click.prevent.stop="{{ $columnWireClickAction }}"
wire:loading.attr="disabled"
wire:target="{{ $columnWireClickAction }}"
@endif
@class([
'fi-ta-col',
'fi-ta-col-has-column-url' => ($columnWrapperTag === 'a') && filled($columnUrl),
])
>
{{ $column }}
</{{ $columnWrapperTag }}>
</td>
@endforeach
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::AfterColumns && (! $isReordering))
<td class="fi-ta-cell">
<div
@class([
'fi-ta-actions',
match ($recordActionsAlignment) {
Alignment::Center => 'fi-align-center',
Alignment::Start, Alignment::Left => 'fi-align-start',
Alignment::Between, Alignment::Justify => 'fi-align-between',
Alignment::End, Alignment::Right => '',
default => is_string($recordActionsAlignment) ? $recordActionsAlignment : '',
},
])
>
@foreach ($recordActions as $action)
{{ $action }}
@endforeach
</div>
</td>
@endif
@if ($isSelectionEnabled && $recordCheckboxPosition === RecordCheckboxPosition::AfterCells && (! $isReordering))
<td
class="fi-ta-cell fi-ta-selection-cell"
>
@if ($isRecordSelectable($record))
<input
aria-label="{{ __('filament-tables::table.fields.bulk_select_record.label', ['key' => $recordKey]) }}"
type="checkbox"
@if ($isSelectionDisabled)
disabled
@elseif ($maxSelectableRecords && ($maxSelectableRecords !== 1))
x-bind:disabled="! areRecordsToggleable([@js($recordKey)])"
@endif
value="{{ $recordKey }}"
x-on:click="toggleSelectedRecord(@js($recordKey))"
x-bind:checked="isRecordSelected(@js($recordKey)) ? 'checked' : null"
data-group="{{ $recordGroupKey }}"
wire:loading.attr="disabled"
wire:target="{{ implode(',', \Filament\Tables\Table::LOADING_TARGETS) }}"
class="fi-ta-record-checkbox fi-checkbox-input"
/>
@endif
</td>
@endif
@if (count($defaultRecordActions) && $recordActionsPosition === RecordActionsPosition::AfterCells && (! $isReordering))
<td class="fi-ta-cell">
<div
@class([
'fi-ta-actions',
match ($recordActionsAlignment) {
Alignment::Center => 'fi-align-center',
Alignment::Start, Alignment::Left => 'fi-align-start',
Alignment::Between, Alignment::Justify => 'fi-align-between',
Alignment::End, Alignment::Right => '',
default => is_string($recordActionsAlignment) ? $recordActionsAlignment : '',
},
])
>
@foreach ($recordActions as $action)
{{ $action }}
@endforeach
</div>
</td>
@endif
</tr>
@endif
@php
$isRecordRowStriped = ! $isRecordRowStriped;
$previousRecord = $record;
$previousRecordGroupKey = $recordGroupKey;
$previousRecordGroupTitle = $recordGroupTitle;
@endphp
@endforeach
@if ($hasSummary && (! $isReordering) && filled($previousRecordGroupTitle) && ((! $records instanceof \Illuminate\Contracts\Pagination\Paginator) || (! $records->hasMorePages())))
@php
$groupColumn = $group->getColumn();
$groupScopedAllTableSummaryQuery = $group->scopeQuery($this->getAllTableSummaryQuery(), $previousRecord);
@endphp
<x-filament-tables::summary.row
:actions="count($defaultRecordActions)"
:actions-position="$recordActionsPosition"
:columns="$columns"
:group-column="$groupColumn"
:groups-only="$isGroupsOnly"
:heading="$isGroupsOnly ? $previousRecordGroupTitle : __('filament-tables::table.summary.subheadings.group', ['group' => $previousRecordGroupTitle, 'label' => $pluralModelLabel])"
:query="$groupScopedAllTableSummaryQuery"
:record-checkbox-position="$recordCheckboxPosition"
:selected-state="$groupedSummarySelectedState[$previousRecordGroupKey] ?? []"
:selection-enabled="$isSelectionEnabled"
/>
@endif
@if ($hasSummary && (! $isReordering))
@php
$groupColumn = $group?->getColumn();
@endphp
<x-filament-tables::summary
:actions="count($defaultRecordActions)"
:actions-position="$recordActionsPosition"
:columns="$columns"
:group-column="$groupColumn"
:groups-only="$isGroupsOnly"
:plural-model-label="$pluralModelLabel"
:record-checkbox-position="$recordCheckboxPosition"
:records="$records"
:selection-enabled="$isSelectionEnabled"
/>
@endif
@endif
</tbody>
@endif
@if (($records !== null) && count($records) && $contentFooter)
<tfoot>
<tr>
{{
$contentFooter->with([
'columns' => $columns,
'records' => $records,
])
}}
</tr>
</tfoot>
@endif
</table>
@elseif ($records === null)
<div class="fi-ta-table-loading-ctn">
{{ \Filament\Support\generate_loading_indicator_html(size: \Filament\Support\Enums\IconSize::TwoExtraLarge) }}
</div>
@endif
</div>
@endif
@if (($records !== null) && ! count($records))
@if ($emptyState = $getEmptyState())
{{ $emptyState }}
@else
<div class="fi-ta-empty-state">
<div class="fi-ta-empty-state-content">
<div class="fi-ta-empty-state-icon-bg">
{{ \Filament\Support\generate_icon_html($getEmptyStateIcon(), size: \Filament\Support\Enums\IconSize::Large) }}
</div>
<{{ $secondLevelHeadingTag }}
class
="fi-ta-empty-state-heading"
>
{{ $getEmptyStateHeading() }}
</{{ $secondLevelHeadingTag }}>
@if (filled($emptyStateDescription = $getEmptyStateDescription()))
<p class="fi-ta-empty-state-description">
{{ $emptyStateDescription }}
</p>
@endif
@if ($emptyStateActions = array_filter(
$getEmptyStateActions(),
fn (\Filament\Actions\Action | \Filament\Actions\ActionGroup $action): bool => $action->isVisible(),
))
<div
class="fi-ta-actions fi-align-center fi-wrapped"
>
@foreach ($emptyStateActions as $action)
{{ $action }}
@endforeach
</div>
@endif
</div>
</div>
@endif
@endif
@if ((($records instanceof \Illuminate\Contracts\Pagination\Paginator) || ($records instanceof \Illuminate\Contracts\Pagination\CursorPaginator)) &&
((! ($records instanceof \Illuminate\Contracts\Pagination\LengthAwarePaginator)) || $records->total()))
@php
$hasExtremePaginationLinks = $hasExtremePaginationLinks();
$paginationPageOptions = $getPaginationPageOptions();
@endphp
<x-filament::pagination
:extreme-links="$hasExtremePaginationLinks"
:page-options="$paginationPageOptions"
:paginator="$records"
/>
@endif
@if ($hasFiltersBelowContent)
<x-filament-tables::filters
:apply-action="$filtersApplyAction"
:form="$filtersForm"
:heading-tag="$secondLevelHeadingTag"
class="fi-ta-filters-below-content"
/>
@endif
</div>
<x-filament-actions::modals />
</div>
@vlados
Copy link
Author

vlados commented Sep 2, 2025

Screenshot 2025-09-02 at 22 56 28 result so far

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment