Advanced

TableBuilder

Basics

Fields and decorations in MoonShine are used inside tables in preview mode.
TableBuilder is responsible for tables.
Using TableBuilder, tables are displayed and filled with data.
You can also use TableBuilder on your own pages or even outside of MoonShine.

TableBuilder::make( Fields|array $fields = [], Paginator|iterable $items = [], ?Paginator $paginator = null )
TableBuilder::make(
Fields|array $fields = [],
Paginator|iterable $items = [],
?Paginator $paginator = null
)

-$fields - fields -$items - field values -$paginator - paginator object

use MoonShine\Components\TableBuilder; TableBuilder::make( [Text::make('Text')], [['text' => 'Value']] )
use MoonShine\Components\TableBuilder;
 
TableBuilder::make(
[Text::make('Text')],
[['text' => 'Value']]
)

Same thing through methods:

TableBuilder::make() ->fields([Text::make('Text')]) ->items([[ 'text' => 'Value' ]])
TableBuilder::make()
->fields([Text::make('Text')])
->items([[ 'text' => 'Value' ]])

Helper table() is also available:

{!! table() ->fields([Text::make('Text')]) ->items([['text' => 'Value']]) !!}
{!!
table()
->fields([Text::make('Text')])
->items([['text' => 'Value']])
!!}

Fields

The fields() method allows you to specify a list of fields to build a table:

TableBuilder::make() ->fields([ Text::make('Text'), ])
TableBuilder::make()
->fields([
Text::make('Text'),
])

Items

The items() method is used to fill the table with data:

TableBuilder::make() ->fields([Text::make('Text')]) ->items([[ 'text' => 'Value' ]])
TableBuilder::make()
->fields([Text::make('Text')])
->items([[ 'text' => 'Value' ]])

The correspondence of data with fields is carried out through the value column fields!

Paginator

The paginator() method for the table to work with pagination:

$paginator = Article::paginate(); TableBuilder::make() ->fields([Text::make('Text')]) ->items($paginator->items()) ->paginator($paginator)
$paginator = Article::paginate();
 
TableBuilder::make()
->fields([Text::make('Text')])
->items($paginator->items())
->paginator($paginator)

Or directly pass the paginator:

TableBuilder::make( items: Article::paginate() ) ->fields([Text::make('Text')])
TableBuilder::make(
items: Article::paginate()
)
->fields([Text::make('Text')])

The TableBuilder works with arrays of items;

if you don't have arrays, you need to cast the paginator to arrays:

$paginator = Article::paginate(); TableBuilder::make() ->fields([Text::make('Text')]) ->items($paginator->through(fn($item) => $item->toArray())) ->paginator($paginator)
$paginator = Article::paginate();
 
TableBuilder::make()
->fields([Text::make('Text')])
->items($paginator->through(fn($item) => $item->toArray()))
->paginator($paginator)

Or you can use cast() method instead.

Casting

The cast() method is used to cast table values to a specific type.
Since by default fields work with primitive types:

use MoonShine\TypeCasts\ModelCast; TableBuilder::make(items: User::paginate()) ->fields([Text::make('Email')]) ->cast(ModelCast::make(User::class))
use MoonShine\TypeCasts\ModelCast;
 
TableBuilder::make(items: User::paginate())
->fields([Text::make('Email')])
->cast(ModelCast::make(User::class))

In this example, we cast the data to the User model format using ModelCast.

For more detailed information, please refer to the section TypeCasts

Buttons

To add new buttons based on ActionButton, use the buttons() method.
Buttons will be added for each row, and when bulk() mode is enabled, they will be displayed in the footer for bulk actions:

TableBuilder::make(items: Article::paginate()) ->fields([ID::make(), Switcher::make('Active')]) ->cast(ModelCast::make(Article::class)) ->buttons([ ActionButton::make('Delete', route('name.delete')), ActionButton::make('Edit', route('name.edit'))->showInDropdown(), ActionButton::make('Go to home', route('home'))->blank()->canSee(fn($data) => $data->active), ActionButton::make('Mass Delete', route('name.mass_delete'))->bulk() ])
TableBuilder::make(items: Article::paginate())
->fields([ID::make(), Switcher::make('Active')])
->cast(ModelCast::make(Article::class))
->buttons([
ActionButton::make('Delete', route('name.delete')),
ActionButton::make('Edit', route('name.edit'))->showInDropdown(),
ActionButton::make('Go to home', route('home'))->blank()->canSee(fn($data) => $data->active),
ActionButton::make('Mass Delete', route('name.mass_delete'))->bulk()
])

Asynchronous mode

If you need to receive data from the table asynchronously (during pagination, sorting), then use the async() method:

async( ?string $asyncUrl = null, string|array|null $asyncEvents = null, ?string $asyncCallback = null )
async(
?string $asyncUrl = null,
string|array|null $asyncEvents = null,
?string $asyncCallback = null
)

-asyncUrl - request url -asyncEvents - events called after a successful request -asyncCallback - js callback function after receiving a response

TableBuilder::make() ->async('/async_url')
TableBuilder::make()
->async('/async_url')

After a successful request, you can raise events by adding the asyncEvents parameter.

TableBuilder::make() ->name('crud') ->async(asyncEvents: ['table-updated-crud', 'form-reset-main-form'])
TableBuilder::make()
->name('crud')
->async(asyncEvents: ['table-updated-crud', 'form-reset-main-form'])

MoonShine already has a set of ready-made events:

  • table-updated-{name} - updating an asynchronous table by its name
  • form-reset-{name} - reset the form values by its name
  • fragment-updated-{name} - updating a blade fragment by its name

The async() method must come after the name() method!

Attributes

You can set any html attributes for the table using the customAttributes() method:

TableBuilder::make() ->customAttributes(['class' => 'custom-table'])
TableBuilder::make()
->customAttributes(['class' => 'custom-table'])

You can set any html attributes for table rows and cells:

TableBuilder::make() ->trAttributes(function( mixed $data, int $row, ComponentAttributeBag $attributes ): ComponentAttributeBag { return $attributes->merge(['class' => 'bgc-green']); })
TableBuilder::make()
->trAttributes(function(
mixed $data,
int $row,
ComponentAttributeBag $attributes
): ComponentAttributeBag {
return $attributes->merge(['class' => 'bgc-green']);
})
TableBuilder::make() ->tdAttributes( function( mixed $data, int $row, int $cell, ComponentAttributeBag $attributes ): ComponentAttributeBag { return $attributes->merge(['class' => 'bgc-red']); } )
TableBuilder::make()
->tdAttributes(
function(
mixed $data,
int $row,
int $cell,
ComponentAttributeBag $attributes
): ComponentAttributeBag {
return $attributes->merge(['class' => 'bgc-red']);
}
)

Missing elements

By default, if the table has no data, it will be empty, but you can display the message "No records yet".
To do this, use the withNotFound() method:

TableBuilder::make() ->withNotFound()
TableBuilder::make()
->withNotFound()

Simplified style

By default, the table is styled as MoonShine,
but using the simple() method you can display the table in a simplified style:

TableBuilder::make() ->simple()
TableBuilder::make()
->simple()

Sticky head

The sticky() method allows you to fix the header when scrolling a table with a large number of elements.

TableBuilder::make() ->sticky()
TableBuilder::make()
->sticky()

Preview

The preview() method disables the display of buttons and sorts for the table:

TableBuilder::make() ->preview()
TableBuilder::make()
->preview()

Vertical mode

Using the vertical() method you can display the table in vertical mode:

TableBuilder::make() ->vertical()
TableBuilder::make()
->vertical()

Adding entries

Using the creatable() method, you can create an "Add" button to generate new records in the table:

creatable( bool $reindex = true, ?int $limit = null, ?string $label = null, ?string $icon = null, array $attributes = [], ?ActionButton $button = null )
creatable(
bool $reindex = true,
?int $limit = null,
?string $label = null,
?string $icon = null,
array $attributes = [],
?ActionButton $button = null
)

-$reindex - editing mode with dynamic name, -$limit - the number of records that can be added -$label - button name -$icon - button icon -$attributes - additional attributes -$button - custom add button.

TableBuilder::make() ->creatable( icon: 'heroicons.outline.pencil', attributes: ['class' => 'my-class'] ) ->fields([ Text::make('Title'), Text::make('Text') ])->items([ ['title' => 'Value 1', 'text' => 'Value 2'], ['title' => '', 'text' => ''] ])
TableBuilder::make()
->creatable(
icon: 'heroicons.outline.pencil',
attributes: ['class' => 'my-class']
)
->fields([
Text::make('Title'),
Text::make('Text')
])->items([
['title' => 'Value 1', 'text' => 'Value 2'],
['title' => '', 'text' => '']
])

In append mode, the last element must be empty (the skeleton of the new entry)!

If the table contains fields in edit mode with a dynamic name, then you need to add a method or parameter reindex:

TableBuilder::make() ->creatable(reindex: true)
TableBuilder::make()
->creatable(reindex: true)

or

TableBuilder::make() ->creatable() ->reindex()
TableBuilder::make()
->creatable()
->reindex()

limit

If you want to limit the number of records that can be added, you must specify the limit parameter:

TableBuilder::make() ->creatable(limit: 6)
TableBuilder::make()
->creatable(limit: 6)

Custom add button

TableBuilder::make() ->creatable( button: ActionButton::make('Foo', '#') )
TableBuilder::make()
->creatable(
button: ActionButton::make('Foo', '#')
)

Editable

By default, fields in the table are displayed in preview mode,
but if you want to display them as editable form elements,
then you need to use the editable() method:

TableBuilder::make() ->editable()
TableBuilder::make()
->editable()

Sortable

To sort rows in a table, use the sortable() method:

TableBuilder::make() ->sortable( url: '/update_indexes_endpoint', key: 'id', group: 'nested' )
TableBuilder::make()
->sortable(
url: '/update_indexes_endpoint',
key: 'id',
group: 'nested'
)

-$url - url handler -$key - element key -$group - grouping.

TableBuilder::make() ->sortable( url: '/update_indexes_endpoint', key: 'id', group: 'nested' )
TableBuilder::make()
->sortable(
url: '/update_indexes_endpoint',
key: 'id',
group: 'nested'
)

Column display

You can let users decide which columns to display in the table, saving the choice.
To do this, you need to set the resource parameter $columnSelection.

columnSelection(string $uniqueId = '')
columnSelection(string $uniqueId = '')

-$uniqueId - unique table Id to save the selection of displayed columns.

TableBuilder::make() ->fields([ Text::make('Title'), Text::make('Text') ]) ->columnSelection('unique-id')
TableBuilder::make()
->fields([
Text::make('Title'),
Text::make('Text')
])
->columnSelection('unique-id')

If you need to exclude fields from selection, use the columnSelection() method.

public function columnSelection(bool $active = true)
public function columnSelection(bool $active = true)
TableBuilder::make() ->fields([ Text::make('Title') ->columnSelection(false), Text::make('Text') ]) ->columnSelection('unique-id')
TableBuilder::make()
->fields([
Text::make('Title')
->columnSelection(false),
Text::make('Text')
])
->columnSelection('unique-id')