In CrudResource
(ModelResource
) on the indexPage
as well as on the DetailPage
, TableBuilder
is used to display the main data,
so we recommend you also study the documentation section TableBuilder.
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\Enums\SortDirection;
class PostResource extends ModelResource
{
protected string $sortColumn = 'created_at';
protected SortDirection $sortDirection = SortDirection::DESC;
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\Enums\SortDirection;
class PostResource extends ModelResource
{
// Default sort field
protected string $sortColumn = 'created_at';
// Default sort type
protected SortDirection $sortDirection = SortDirection::DESC;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\Enums\SortDirection;
class PostResource extends ModelResource
{
// Default sort field
protected string $sortColumn = 'created_at';
// Default sort type
protected SortDirection $sortDirection = SortDirection::DESC;
// ...
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\Enums\SortDirection;
class PostResource extends ModelResource
{
// Default sort field
protected string $sortColumn = 'created_at';
// Default sort type
protected SortDirection $sortDirection = SortDirection::DESC;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\Enums\SortDirection;
class PostResource extends ModelResource
{
// Default sort field
protected string $sortColumn = 'created_at';
// Default sort type
protected SortDirection $sortDirection = SortDirection::DESC;
// ...
}
To add buttons to the table, you can use ActionButton
and the methods indexButtons()
, as well as detailButtons()
for the detail page.
After the main buttons:
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint'));
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint'));
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint'));
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint'));
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint'));
}
Before the main buttons:
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->prepend(ActionButton::make('Link', '/endpoint'));
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->prepend(ActionButton::make('Link', '/endpoint'));
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->prepend(ActionButton::make('Link', '/endpoint'));
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->prepend(ActionButton::make('Link', '/endpoint'));
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->prepend(ActionButton::make('Link', '/endpoint'));
}
Remove the delete button:
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->except(fn(ActionButton $btn) => $btn->getName() === 'resource-delete-button');
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->except(fn(ActionButton $btn) => $btn->getName() === 'resource-delete-button');
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->except(fn(ActionButton $btn) => $btn->getName() === 'resource-delete-button');
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->except(fn(ActionButton $btn) => $btn->getName() === 'resource-delete-button');
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->except(fn(ActionButton $btn) => $btn->getName() === 'resource-delete-button');
}
Clear the button set and add your own:
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
parent::indexButtons()
->empty()
->add(ActionButton::make('Link', '/endpoint'));
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
parent::indexButtons()
->empty()
->add(ActionButton::make('Link', '/endpoint'));
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
parent::indexButtons()
->empty()
->add(ActionButton::make('Link', '/endpoint'));
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
parent::indexButtons()
->empty()
->add(ActionButton::make('Link', '/endpoint'));
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
parent::indexButtons()
->empty()
->add(ActionButton::make('Link', '/endpoint'));
}
The same approach is used for the table on the detail page, only through the method detailButtons()
.
For bulk actions, you need to add the bulk()
method.
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint')->bulk());
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint')->bulk());
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint')->bulk());
}
namespaces
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint')->bulk());
}
use MoonShine\Support\ListOf;
use MoonShine\UI\Components\ActionButton;
protected function indexButtons(): ListOf
{
return parent::indexButtons()
->add(ActionButton::make('Link', '/endpoint')->bulk());
}
By default, all buttons in the table are displayed in a line, but you can change the behavior and display them through a drop-down list.
To do this, change the $indexButtonsInDropdown
property in the resource:
class PostResource extends ModelResource
{
protected bool $indexButtonsInDropdown = true;
}
class PostResource extends ModelResource
{
protected bool $indexButtonsInDropdown = true;
// ...
}
class PostResource extends ModelResource
{
protected bool $indexButtonsInDropdown = true;
// ...
}
class PostResource extends ModelResource
{
protected bool $indexButtonsInDropdown = true;
// ...
}
class PostResource extends ModelResource
{
protected bool $indexButtonsInDropdown = true;
// ...
}
To add attributes for the td
element of the table, you can use the customWrapperAttributes()
method on the field that represents the cell you need.
use MoonShine\UI\Fields\Text;
protected function indexFields(): iterable
{
return [
Text::make('Title')
->customWrapperAttributes(['width' => '20%']);
];
}
namespaces
use MoonShine\UI\Fields\Text;
protected function indexFields(): iterable
{
return [
// ...
Text::make('Title')
->customWrapperAttributes(['width' => '20%']);
];
}
use MoonShine\UI\Fields\Text;
protected function indexFields(): iterable
{
return [
// ...
Text::make('Title')
->customWrapperAttributes(['width' => '20%']);
];
}
namespaces
use MoonShine\UI\Fields\Text;
protected function indexFields(): iterable
{
return [
// ...
Text::make('Title')
->customWrapperAttributes(['width' => '20%']);
];
}
use MoonShine\UI\Fields\Text;
protected function indexFields(): iterable
{
return [
// ...
Text::make('Title')
->customWrapperAttributes(['width' => '20%']);
];
}
You can also customize tr
and td
for the table with data through the resource.
To do this, you need to use the corresponding methods trAttributes()
and tdAttributes()
,
to which you need to pass a closure that returns an array of attributes for the table component.
namespace App\MoonShine\Resources;
use Closure;
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\Text;
class PostResource extends ModelResource
{
protected function tdAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row, int $cell) => [
'width' => '20%'
];
}
protected function trAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row) => [
'data-tr' => $row
];
}
}
namespaces
namespace App\MoonShine\Resources;
use Closure;
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\Text;
class PostResource extends ModelResource
{
// ...
protected function tdAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row, int $cell) => [
'width' => '20%'
];
}
protected function trAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row) => [
'data-tr' => $row
];
}
}
namespace App\MoonShine\Resources;
use Closure;
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\Text;
class PostResource extends ModelResource
{
// ...
protected function tdAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row, int $cell) => [
'width' => '20%'
];
}
protected function trAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row) => [
'data-tr' => $row
];
}
}
namespaces
namespace App\MoonShine\Resources;
use Closure;
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\Text;
class PostResource extends ModelResource
{
// ...
protected function tdAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row, int $cell) => [
'width' => '20%'
];
}
protected function trAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row) => [
'data-tr' => $row
];
}
}
namespace App\MoonShine\Resources;
use Closure;
use MoonShine\Contracts\Core\TypeCasts\DataWrapperContract;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\Text;
class PostResource extends ModelResource
{
// ...
protected function tdAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row, int $cell) => [
'width' => '20%'
];
}
protected function trAttributes(): Closure
{
return fn(?DataWrapperContract $data, int $row) => [
'data-tr' => $row
];
}
}

By default, clicking on tr
does nothing, but you can change the behavior to navigate to editing, selection, or to the detailed view.
use MoonShine\Support\Enums\ClickAction;
protected ?ClickAction $clickAction = ClickAction::SELECT;
namespaces
use MoonShine\Support\Enums\ClickAction;
// ClickAction::SELECT, ClickAction::DETAIL, ClickAction::EDIT
protected ?ClickAction $clickAction = ClickAction::SELECT;
use MoonShine\Support\Enums\ClickAction;
// ClickAction::SELECT, ClickAction::DETAIL, ClickAction::EDIT
protected ?ClickAction $clickAction = ClickAction::SELECT;
namespaces
use MoonShine\Support\Enums\ClickAction;
// ClickAction::SELECT, ClickAction::DETAIL, ClickAction::EDIT
protected ?ClickAction $clickAction = ClickAction::SELECT;
use MoonShine\Support\Enums\ClickAction;
// ClickAction::SELECT, ClickAction::DETAIL, ClickAction::EDIT
protected ?ClickAction $clickAction = ClickAction::SELECT;
The model resource property stickyTable
allows you to fix the header when scrolling a table with a large number of elements.
namespace App\MoonShine\Resources;
use MoonShine\Laravle\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyTable = true;
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravle\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyTable = true;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravle\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyTable = true;
// ...
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravle\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyTable = true;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravle\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyTable = true;
// ...
}
You can allow users to independently determine which columns to display in the table while retaining their selection.
To do this, you need to set the parameter $columnSelection
for the resource.
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
// ...
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
// ...
}
If you need to exclude fields from the selection, use the columnSelection()
method.
public function columnSelection(bool $active = true, bool $hideOnInit = false)
public function columnSelection(bool $active = true, bool $hideOnInit = false)
public function columnSelection(bool $active = true, bool $hideOnInit = false)
public function columnSelection(bool $active = true, bool $hideOnInit = false)
public function columnSelection(bool $active = true, bool $hideOnInit = false)
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Textarea;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
protected function indexFields(): iterable
{
return [
ID::make()
->columnSelection(false),
Text::make('Title'),
Textarea::make('Body'),
];
}
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Textarea;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
// ...
protected function indexFields(): iterable
{
return [
ID::make()
->columnSelection(false),
Text::make('Title'),
Textarea::make('Body'),
];
}
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Textarea;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
// ...
protected function indexFields(): iterable
{
return [
ID::make()
->columnSelection(false),
Text::make('Title'),
Textarea::make('Body'),
];
}
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Textarea;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
// ...
protected function indexFields(): iterable
{
return [
ID::make()
->columnSelection(false),
Text::make('Title'),
Textarea::make('Body'),
];
}
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Text;
use MoonShine\UI\Fields\Textarea;
class PostResource extends ModelResource
{
protected bool $columnSelection = true;
// ...
protected function indexFields(): iterable
{
return [
ID::make()
->columnSelection(false),
Text::make('Title'),
Textarea::make('Body'),
];
}
}
If you need to hide the default field:
->columnSelection(hideOnInit: true)
->columnSelection(hideOnInit: true)
->columnSelection(hideOnInit: true)
->columnSelection(hideOnInit: true)
->columnSelection(hideOnInit: true)
You can freeze cells in large tables, suitable for ID columns and buttons.
To fix buttons in the table, switch the resource to stickyButtons
mode.
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyButtons = true;
}
namespaces
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyButtons = true;
// ...
}
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyButtons = true;
// ...
}
namespaces
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyButtons = true;
// ...
}
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $stickyButtons = true;
// ...
}
To fix a column, call the sticky()
method on the Field.
use MoonShine\UI\Fields\ID;
protected function indexFields(): iterable
{
return [
ID::make()->sticky(),
];
}
namespaces
use MoonShine\UI\Fields\ID;
protected function indexFields(): iterable
{
return [
ID::make()->sticky(),
];
}
use MoonShine\UI\Fields\ID;
protected function indexFields(): iterable
{
return [
ID::make()->sticky(),
];
}
namespaces
use MoonShine\UI\Fields\ID;
protected function indexFields(): iterable
{
return [
ID::make()->sticky(),
];
}
use MoonShine\UI\Fields\ID;
protected function indexFields(): iterable
{
return [
ID::make()->sticky(),
];
}
To change the number of items per page, use the property $itemsPerPage
.
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected int $itemsPerPage = 25;
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected int $itemsPerPage = 25;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected int $itemsPerPage = 25;
// ...
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected int $itemsPerPage = 25;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected int $itemsPerPage = 25;
// ...
}
When dealing with a large volume of data, the best solution is to use cursor pagination.
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $cursorPaginate = true;
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $cursorPaginate = true;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $cursorPaginate = true;
// ...
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $cursorPaginate = true;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $cursorPaginate = true;
// ...
}
If you do not plan to display the total number of pages, use Simple Pagination
.
This avoids additional queries for the total number of records in the database.
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $simplePaginate = true;
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $simplePaginate = true;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $simplePaginate = true;
// ...
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $simplePaginate = true;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $simplePaginate = true;
// ...
}

If you do not plan to use pagination, it can be disabled.
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $usePagination = false;
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $usePagination = false;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $usePagination = false;
// ...
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $usePagination = false;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $usePagination = false;
// ...
}
In the resource, async mode is used by default.
This mode allows for pagination, filtering, and sorting without page reloads.
However, if you want to disable async mode, you can use the property $isAsync
.
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isAsync = false;
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isAsync = false;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isAsync = false;
// ...
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isAsync = false;
// ...
}
namespace App\MoonShine\Resources;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isAsync = false;
// ...
}
You can asynchronously update a row in the table by triggering the event:
table-row-updated-{{componentName}}-{{row-id}}
table-row-updated-{{componentName}}-{{row-id}}
table-row-updated-{{componentName}}-{{row-id}}
table-row-updated-{{componentName}}-{{row-id}}
table-row-updated-{{componentName}}-{{row-id}}
{{componentName}}
- the name of the component;
{{row-id}}
- the key of the row item.
To add an event, you can use the helper class:
AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
{row-id}
- shortcode for the id of the current model record.
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
class PostResource extends ModelResource
{
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->updateOnPreview(
events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'index-table-{row-id}')]
)
];
}
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
class PostResource extends ModelResource
{
// ...
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->updateOnPreview(
events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'index-table-{row-id}')]
)
];
}
}
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
class PostResource extends ModelResource
{
// ...
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->updateOnPreview(
events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'index-table-{row-id}')]
)
];
}
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
class PostResource extends ModelResource
{
// ...
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->updateOnPreview(
events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'index-table-{row-id}')]
)
];
}
}
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
use MoonShine\Support\AlpineJs;
use MoonShine\Support\Enums\JsEvent;
class PostResource extends ModelResource
{
// ...
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->updateOnPreview(
events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'index-table-{row-id}')]
)
];
}
}
The withUpdateRow()
method is also available, which helps simplify the assignment of events.
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->withUpdateRow($this->getListComponentName())
];
}
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
// ...
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->withUpdateRow($this->getListComponentName())
];
}
}
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
// ...
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->withUpdateRow($this->getListComponentName())
];
}
}
namespaces
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
// ...
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->withUpdateRow($this->getListComponentName())
];
}
}
namespace App\MoonShine\Resources;
use MoonShine\UI\Fields\ID;
use MoonShine\UI\Fields\Switcher;
use MoonShine\UI\Fields\Text;
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
// ...
protected function indexFields(): iterable
{
return [
ID::make(),
Text::make('Title'),
Switcher::make('Active')
->withUpdateRow($this->getListComponentName())
];
}
}
If you want to display a page without waiting for data to load, and then send a query to get the table data, use Lazy mode.
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isLazy = true;
}
namespaces
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isLazy = true;
}
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isLazy = true;
}
namespaces
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isLazy = true;
}
use MoonShine\Laravel\Resources\ModelResource;
class PostResource extends ModelResource
{
protected bool $isLazy = true;
}
You can completely replace or modify the resource's TableBuilder
for both the index and detail pages.
Use the modifyListComponent()
or modifyDetailComponent()
methods for this.
use MoonShine\Contracts\UI\ComponentContract;
public function modifyListComponent(ComponentContract $component): ComponentContract
{
return parent::modifyListComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
namespaces
use MoonShine\Contracts\UI\ComponentContract;
public function modifyListComponent(ComponentContract $component): ComponentContract
{
return parent::modifyListComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
use MoonShine\Contracts\UI\ComponentContract;
public function modifyListComponent(ComponentContract $component): ComponentContract
{
return parent::modifyListComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
namespaces
use MoonShine\Contracts\UI\ComponentContract;
public function modifyListComponent(ComponentContract $component): ComponentContract
{
return parent::modifyListComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
use MoonShine\Contracts\UI\ComponentContract;
public function modifyListComponent(ComponentContract $component): ComponentContract
{
return parent::modifyListComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
use MoonShine\Contracts\UI\ComponentContract;
public function modifyDetailComponent(ComponentContract $component): ComponentContract
{
return parent::modifyDetailComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
namespaces
use MoonShine\Contracts\UI\ComponentContract;
public function modifyDetailComponent(ComponentContract $component): ComponentContract
{
return parent::modifyDetailComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
use MoonShine\Contracts\UI\ComponentContract;
public function modifyDetailComponent(ComponentContract $component): ComponentContract
{
return parent::modifyDetailComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
namespaces
use MoonShine\Contracts\UI\ComponentContract;
public function modifyDetailComponent(ComponentContract $component): ComponentContract
{
return parent::modifyDetailComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
use MoonShine\Contracts\UI\ComponentContract;
public function modifyDetailComponent(ComponentContract $component): ComponentContract
{
return parent::modifyDetailComponent($component)->customAttributes([
'data-my-attr' => 'value'
]);
}
If it is not enough to just automatically output fields in thead
, tbody
, and tfoot
,
you can override or extend this logic based on the resource methods thead()
, tbody()
, tfoot()
.
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
protected function thead(): null|TableRowsContract|Closure
{
return static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tbody(): null|TableRowsContract|Closure
{
return static fn(TableRowsContract $default) => $default->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tfoot(): null|TableRowsContract|Closure
{
return static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
namespaces
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
protected function thead(): null|TableRowsContract|Closure
{
return static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tbody(): null|TableRowsContract|Closure
{
return static fn(TableRowsContract $default) => $default->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tfoot(): null|TableRowsContract|Closure
{
return static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
protected function thead(): null|TableRowsContract|Closure
{
return static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tbody(): null|TableRowsContract|Closure
{
return static fn(TableRowsContract $default) => $default->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tfoot(): null|TableRowsContract|Closure
{
return static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
namespaces
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
protected function thead(): null|TableRowsContract|Closure
{
return static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tbody(): null|TableRowsContract|Closure
{
return static fn(TableRowsContract $default) => $default->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tfoot(): null|TableRowsContract|Closure
{
return static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
protected function thead(): null|TableRowsContract|Closure
{
return static fn(TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tbody(): null|TableRowsContract|Closure
{
return static fn(TableRowsContract $default) => $default->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
protected function tfoot(): null|TableRowsContract|Closure
{
return static fn(?TableRowContract $default) => TableRows::make([$default])->pushRow(
TableCells::make()->pushCell(
'td content'
)
);
}
Example of adding a row in tfoot
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Table\TableRow;
protected function tfoot(): null|TableRowsContract|Closure
{
return static function(?TableRowContract $default, TableBuilder $table) {
$cells = TableCells::make();
$cells->pushCell('Balance:');
$cells->pushCell('$1000');
return TableRows::make([TableRow::make($cells), $default]);
};
}
namespaces
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Table\TableRow;
protected function tfoot(): null|TableRowsContract|Closure
{
return static function(?TableRowContract $default, TableBuilder $table) {
$cells = TableCells::make();
$cells->pushCell('Balance:');
$cells->pushCell('$1000');
return TableRows::make([TableRow::make($cells), $default]);
};
}
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Table\TableRow;
protected function tfoot(): null|TableRowsContract|Closure
{
return static function(?TableRowContract $default, TableBuilder $table) {
$cells = TableCells::make();
$cells->pushCell('Balance:');
$cells->pushCell('$1000');
return TableRows::make([TableRow::make($cells), $default]);
};
}
namespaces
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Table\TableRow;
protected function tfoot(): null|TableRowsContract|Closure
{
return static function(?TableRowContract $default, TableBuilder $table) {
$cells = TableCells::make();
$cells->pushCell('Balance:');
$cells->pushCell('$1000');
return TableRows::make([TableRow::make($cells), $default]);
};
}
use Closure;
use MoonShine\Contracts\UI\Collection\TableRowsContract;
use MoonShine\Contracts\UI\TableRowContract;
use MoonShine\UI\Collections\TableCells;
use MoonShine\UI\Collections\TableRows;
use MoonShine\UI\Components\Table\TableBuilder;
use MoonShine\UI\Components\Table\TableRow;
protected function tfoot(): null|TableRowsContract|Closure
{
return static function(?TableRowContract $default, TableBuilder $table) {
$cells = TableCells::make();
$cells->pushCell('Balance:');
$cells->pushCell('$1000');
return TableRows::make([TableRow::make($cells), $default]);
};
}