Tables
The list page of a resource is described by collection(). In code the
class is Anvil\Collection\Collection: it holds the columns, filters,
sorting, page sizes and how records look as table rows and as cards. Users
switch between table and cards, search, filter, sort, hide columns and
save views.
The example is the people list of AnvilIAM (shortened): a computed name with a second line, icons on dates, counts of related records, a hint coloured like the record, and cards with several areas.
use Anvil\Collection\Collection;use Anvil\Collection\Columns\CountColumn;use Anvil\Collection\Columns\TextColumn;use Anvil\Collection\Filters\DateRangeFilter;use Anvil\Collection\Filters\SelectFilter;
public function collection(Collection $collection): Collection{ return $collection ->columns([ TextColumn::make('name') ->state(fn ($person): string => $this->recordTitle($person)) ->queryColumn('people.last_name', 'people.first_name')->sortable()->searchable() ->description('cost_center'), TextColumn::make('personnel_number')->sortable()->searchable()->link('hr'), TextColumn::make('entry_date')->date()->icon('box-arrow-in-right')->sortable(), TextColumn::make('exit_date')->date()->icon('box-arrow-right')->sortable()->toggleable(), TextColumn::make('hint') ->state(static fn ($person): ?string => self::hint($person)) // "joins in 3 days" ->color(static fn ($hint, $person): ?string => self::tone($person)), CountColumn::make('open_tasks')->label('Open tasks') ->relation(FulfilmentTaskModel::class, 'person_id', static fn (Model $tasks) => $tasks->where('status', 'open')) ->icon('list-check'), TextColumn::make('status') ->labels(['planned' => 'Planned', 'active' => 'Active', 'left' => 'Left']) ->badge(['active' => 'success', 'planned' => 'info', 'left' => 'secondary']), ]) ->filters([ SelectFilter::make('status')->options(['planned' => 'Planned', 'active' => 'Active', 'left' => 'Left']), DateRangeFilter::make('entry_date'), ]) // Blue: joins soon; orange: has left. ->tone(static fn ($person): ?string => self::tone($person)) ->card( title: 'name', description: 'personnel_number', badges: ['status'], meta: ['entry_date', 'exit_date'], rows: [['hint'], ['open_tasks']], ) ->defaultSort('name') ->perPage(25, [10, 25, 50, 100]);}Parts of a list
Section titled “Parts of a list”| Part | Described by | Details |
|---|---|---|
| Columns | columns([...]) |
Columns |
| Filters | filters([...]) |
Filters |
| Search | searchable() columns |
Search |
| Cards | card(...) |
Cards |
| Actions per record, bulk actions, export | Resource::actions(), bulkActions(), $exportable |
Actions in lists |
| Key figures above the list | Resource::listWidgets() |
Widgets above the list |
| Remembered layout, saved views, presets | presets([...]) |
Saved views |
| Permissions, policies, validation of requests | Security |
Collection options
Section titled “Collection options”| Option | Default | Effect |
|---|---|---|
columns([...]) |
– | Columns: TextColumn, CountColumn or own columns |
filters([...]) |
[] |
Filters in the toolbar |
defaultSort('name', 'asc') |
newest first (UUIDv7) | Sort when the list is opened; the column must be sortable() |
perPage(25, [10, 25, 50, 100]) |
25 | Page size and the sizes users can choose |
views([Collection::VIEW_TABLE, Collection::VIEW_CARDS], default: …) |
table and cards, table first | Available views; the switch is shown with more than one |
card(title:, description:, badges:, meta:, rows:, fields:, view:) |
first column as title, other columns as fields | Content of the cards, see Cards |
tone(fn ($record) => 'warning') |
none | Colour of a record as table row and card, see Colours and icons |
rowActions(table: 3, cards: 2) |
3 and 2 | Actions shown as buttons per record, see Actions in lists |
presets([...]) |
none | Views defined in code, see Presets |
emptyState('No invoices yet.') |
“No records found.” | Text of an empty list |
views() restricts the list to one view or sets the default:
$collection->views([Collection::VIEW_TABLE, Collection::VIEW_CARDS], default: Collection::VIEW_CARDS);What users can do
Section titled “What users can do”- Sort by the header of a
sortable()column; a second click reverses the order. - Search the
searchable()columns with words, phrases and*. - Filter with the controls of the toolbar; active filters are counted and Reset filters clears them.
- Page through the records and choose the page size.
- Switch between table and cards, hide
toggleable()columns. - Save the current state as a view, or open a preset.
- Open a record: the first column of a row (and the card title) links to the detail page if the user may view the record and the column has no link of its own.
Every change reloads only the list (htmx), not the page. Changing the search, a filter or the page size starts on page 1 again. What the user wants to keep is saved as a view.
Related lists
Section titled “Related lists”Relations on the detail page (see Related records) show the collection of the related resource with the same columns, filters and actions, restricted to the records of the parent. They offer the column menu, but neither remember the layout nor offer saved views or widgets.