Table

# Properties

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $sortColumn = ''; // Default sort field
 
protected string $sortDirection = 'DESC'; // Default sort type
 
protected int $itemsPerPage = 25; // Number of elements per page
 
//...
}

# Buttons

To add buttons to the table, use ActionButton and the indexButtons or buttons methods in the resource

public function indexButtons(): array
{
return [
ActionButton::make('Link', '/endpoint'),
];
}

An example of creating custom buttons for the index table in the section Recipes

For bulk actions you need to add the bulk method

public function indexButtons(): array
{
return [
ActionButton::make('Link', '/endpoint')->bulk(),
];
}

You can also use the buttons method, but in this case the buttons will be on all other pages of the resource

public function buttons(): array
{
return [
ActionButton::make('Link', '/endpoint'),
];
}

# Attributes

Through model resources, it is possible to customize the data table tr and td.
To do this, you must use the appropriate trAttributes() and tdAttributes() methods, which need to pass a closure that returns attributes for the table component.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use Closure;
use Illuminate\View\ComponentAttributeBag;
use MoonShine\Fields\Text;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
//...
 
public function trAttributes(): Closure
{
return function (
Model $item,
int $row,
ComponentAttributeBag $attr
): ComponentAttributeBag {
if ($item->id === 1 | $row === 2) {
$attr->setAttributes([
'class' => 'bgc-green'
]);
}
 
return $attr;
};
}
 
public function tdAttributes(): Closure
{
return function (
Model $item,
int $row,
int $cell,
ComponentAttributeBag $attr = null
): ComponentAttributeBag {
if ($cell === 6) {
$attr->setAttributes([
'class' => 'bgc-red'
]);
}
 
return $attr;
};
}
 
//...
}

# Click Actions

By default, nothing will happen when clicking tr, but you can change the behavior to go to edit, select or go to detailed view

// Resource property
// ClickAction::SELECT, ClickAction::DETAIL, ClickAction::EDIT
 
protected ?ClickAction $clickAction = ClickAction::SELECT;

# Simple pagination

If you don't plan to display the total number of pages, use Simple Pagination. This will avoid additional queries for the total number of records in the database.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $simplePaginate = true;
 
// ...
}

# Disabling pagination

If you don't plan to use pagination, you can turn it off.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $usePagination = false;
 
// ...
}

# Asynchronous mode

Switch mode without reboot for filtering, sorting and pagination

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Resources\ModelResource;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $isAsync = true;
 
// ...
}

# Updating a row

You can update a row of a table asynchronously; to do this, you need to trigger the event:

table-row-updated-{{componentName}}-{{row-key}}
  • {{componentName}} - name of the component;
  • {{row-key}} - row key.

To add an event, you can use the helper class:

AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'main-table-{row-id}')
  • {row-id} - shortcode for the id of the current model record.

The presence of the ID field and asynchronous mode are required.

namespace App\MoonShine\Resources;
 
use App\Models\Post;
use MoonShine\Enums\JsEvent;
use MoonShine\Fields\ID;
use MoonShine\Fields\Switcher;
use MoonShine\Fields\Text;
use MoonShine\Fields\Textarea;
use MoonShine\Resources\ModelResource;
use MoonShine\Support\AlpineJs;
 
class PostResource extends ModelResource
{
protected string $model = Post::class;
 
protected string $title = 'Posts';
 
protected bool $isAsync = true;
 
//...
 
public function fields(): array
{
return [
ID::make(),
Text::make('Title'),
Textarea::make('Body'),
Switcher::make('Active')
->updateOnPreview(
events: [AlpineJs::event(JsEvent::TABLE_ROW_UPDATED, 'index-table-{row-id}')]
)
];
}
 
//...
}

The withUpdateRow() method is also available to help simplify event assignment:

TableBuilder::make()
->fields([
ID::make()->sortable(),
Text::make('Title'),
Textarea::make('Body'),
Switcher::make('Active')
->withUpdateRow('main-table')
])
->items($this->fetch())
->name('main-table')
->async(),