Adminix Documentation Help

List

Description

The "List" module purpose - render list of some records from your database to work with them.

When the resolved list has no rows, Adminix renders a single No records found. table row. The empty state uses the same table width and responsive scroll container as regular records, including relation manager child lists.

  1. Configuration

  2. Lenses

  3. Fields

  4. Row details

  5. Column visibility

  6. Density and sticky table controls

  7. Searching

  8. Filters

  9. Reset controls

  10. Mobile behavior

  11. Bulk actions

  12. Actions

  13. New item link

  14. Appearance examples

Configuration

Basic example:

use App\Models\User; use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\List\ListModule; ... $page = new AdminixPage(); ... $page->addModule( ListModule::name('users') ->title('USERS') ->dataSource(User::class) ->pagination(20) ->addFields(...) ) ...

To add to the page List module you need paste AlexKudrya\Adminix\Modules\List\ListModule class instance as an argument to addModule or addModules method of AdminixPage object.

ListModule configuration

Full settings list:

Method

Description

name

Name of module, must be unique in current page.

name('users')

Required

title

Title on the top of the module

title('USERS')

Optional

pagination

Number of items per page. To disable pagination must be equal to 0 or not exist.

pagination(20)

Optional

dataSource

Source of data for List, can be an Eloquent Model - \App\Models\User::class or name of table in database users or public.users

dataSource(\App\Models\User::class)

Required

withDeleted

Determines render or not deleted records (working with models with included SoftDeletes trait)

By default, is not active

withDeleted()

Optional

hiddenOnIndex / hideOnIndex

Removes the field from the server-rendered index table and from inline-edit writable field resolution. Use this for server-side list visibility, not for browser-only column preferences.

hiddenOnIndex() hideOnIndex()

Optional

editable

Determines possibility to edit records directly in the List. Editable possibility for every field determines in his personal config. By default, is not active

editable(),

Optional

primaryKey

Primary key in source table. Used for editable mode. Usually it is "id"

primaryKey('id')

Required if editable mode is enabled

criteria

Database Builder criteria to render records. For example to not show administrator you need paste this:

criteria([ ['is_admin', '=', false] ])

Or you can paste parameter from route:

criteria([ ['user_id', '=', 'param:1'] ])

For example, for https://site.com/adminix/comments/21 it will be mean that you need all comments where user_id ==21.

Module/query criteria are normalized through Adminix's shared criteria contract. Supported operators are =, ==, !=, <>, >, <, >=, <=, like, and not like; == is normalized to =. Array values support only equality operators and become whereIn/whereNotIn. Null values support only equality operators and become whereNull/whereNotNull.

Optional

resource

Laravel JsonResource to provide data. Example: \App\Http\Resources\UserAdminResource::class

resource(\App\Http\Resources\UserAdminResource::class)

Optional

addLens


addLenses

Add server-defined saved views for the current list. Each lens can apply extra criteria, lens-specific default sorting, and explicit withDeleted().

addLenses( ListLens::name('active') ->title('Active') ->criteria(['status' => 'active']), ListLens::name('trash') ->title('Trash') ->withDeleted() )

Detailed settings described below. #Lenses

Optional

addField


addFields

Methods by which you can add fields to List for displaying.

Arguments can be only AlexKudrya\Adminix\Modules\List\ListField class instances.

Detailed here #Fields

addField( ListField::name('Name') ->field('name') ->type(ListFieldTypeEnum::STRING) ->sortable() )

Required

rowDetails

Attach a server-declared expandable detail panel to each row. The panel reuses DetailField renderers and reads only fields configured in PHP.

rowDetails( ListRowDetails::make('Details') ->columns(2) ->addFields( DetailField::make('Status', 'status')->badge('#754195'), DetailField::make('Payload', 'metadata')->json() ) )

Detailed settings described below. #Row details

Optional

search

Render "Search" input on the top of module.

Argument - AlexKudrya\Adminix\Modules\List\ListSearch class instance.

search( ListSearch::searchFields(['name', 'email']) ->placeholder('Search users') )

Detailed settings described below. #Searching

Optional

addFilter


addFilters

Methods by which you can add filters for current List.

Arguments can be only several classes instances:

  • AlexKudrya\Adminix\Modules\List\ListFilter

  • AlexKudrya\Adminix\Modules\List\ListDateFilter

  • AlexKudrya\Adminix\Modules\List\ListDateRangeFilter

->addFilters( ListFilter::field('role_id') ->name('Role') ->src( InputSelectSrc::nameField('name') ->valueField('id') ->dataSource(UserRole::class) ), ListDateRangeFilter::field('created_at') ->name('Registration time') ->withTime() )

Detailed settings described below. #Filters

Optional

columnVisibility

Add a Columns section to the list settings menu for hideable list fields. Column state is UI-only and stored in browser local storage by list name.

columnVisibility()

Detailed settings described below. #Column visibility

Optional

densitySwitcher

Add table density controls to the list settings menu. The switcher is browser-only and stores compact/comfortable state by list name.

densitySwitcher()

Detailed settings described below. #Density and sticky table controls

Optional

stickyHeader

Keep the table header visible while scrolling inside the table container.

stickyHeader()

Detailed settings described below. #Density and sticky table controls

Optional

stickyActions

Keep the row action column visible while scrolling wide tables horizontally. It uses the existing row action buttons/forms/modal togglers.

stickyActions()

Detailed settings described below. #Density and sticky table controls

Optional

rowActionsDropdown

Render row actions behind one vertical three-dots dropdown button instead of inline buttons. This is only a presentation option; row action definitions, criteria, methods, params, CSRF forms, tooltips, and modal togglers stay server-defined.

rowActionsDropdown()

Detailed settings described below. #Actions

Optional

resetControls

Add an opt-in "Reset view" action to the list settings menu for the current list state. The control removes current list search, filters, sorting, active lens, and pagination from the URL.

resetControls()

Detailed settings described below. #Reset controls

Optional

addAction


addActions

Methods by which you can add action buttons (Links) for every item in current List module.

Arguments can be only several classes instances:

  • AlexKudrya\Adminix\Modules\Link\AdminixLinkModule

  • AlexKudrya\Adminix\Modules\Link\LinkModule

addAction( AdminixLinkModule::name('user_details') ->title('DETAILS') ->icon('bi bi-pencil') ->uri(UserPage::URI) ->params(['record:id']), )

Detailed settings described below. #Actions

Optional

addBulkAction


addBulkActions

Methods by which you can add server-side batch actions for selected rows in current List module.

Arguments can be only AlexKudrya\Adminix\Modules\List\BulkAction class instances.

addBulkAction( BulkAction::make('mark_paid') ->title('Mark paid') ->icon('bi bi-check2') ->confirm('Mark selected orders as paid?') ->handler(MarkOrdersPaidAction::class) )

Detailed settings described below. #Bulk actions

Optional

sorting

Basic sorting for records in current List module.

Argument can be only AlexKudrya\Adminix\Modules\Sorting class instance.

Example:

sorting( Sorting::field('id') ->direction('asc') )

Optional

newItemLink

Setting for "New Item" button rendered between Title and List, near to Search input. When a list has both create and search controls, Adminix keeps them grouped on the left side of the list toolbar.

Format is similar to Adminix Link module.

newItemLink( AdminixLinkModule::name('new_user_btn') ->title('NEW USER') ->icon('bi bi-person-fill-add') ->uri(NewUserPage::URI) )

Detailed here #New item link

Optional

Lenses

Lenses are server-defined saved views for ListModule. They are useful for common list presets such as Active, Drafts, Deleted, VIP, or Needs review.

The active lens is selected by the query key lens-{moduleName}. Adminix resolves this value only against lenses configured in PHP. Unknown lens names are ignored and the default list is rendered.

use AlexKudrya\Adminix\Modules\List\ListLens; use AlexKudrya\Adminix\Modules\List\ListModule; use AlexKudrya\Adminix\Modules\Sorting; ListModule::name('users') ->dataSource(User::class) ->addLenses( ListLens::name('active') ->title('Active') ->criteria(['status' => 'active']) ->filters(['verified' => '1']) ->sorting( Sorting::field('created_at') ->direction('desc') ), ListLens::name('deleted') ->title('Deleted') ->withDeleted() ->criteria([ ['deleted_at', '!=', null], ]) ) ->addFields(...);

Lens criteria are applied after base ListModule::criteria() and before user filters, search, and sorting. Lens filters are defaults for configured list filters. Use the filter field as the key:

ListLens::name('needs-review') ->title('Needs review') ->filters([ 'status' => 'pending', 'created_at' => [ 'from' => '2026-01-01', 'to' => '2026-01-31', ], ]);

Result: when the URL contains lens-users=needs-review and does not contain filter-users-status, Adminix applies status = pending and shows the filter as selected. If the URL already contains filter-users-status, the request value wins and the lens default is not used. Date range defaults can use a nested from/to map or flat keys such as created_at-from. Lens sorting is a default sorting only: if the request contains a valid sort-{module}-{field} parameter, the user-selected sorting wins. Pagination links keep the active lens query parameter.

Use base criteria() for mandatory tenant/user scoping. Use lenses only for alternate server-owned views inside that scope.

Fields

Fields is an array, of fields to be rendered in the List.

To add Field to the List module you need paste AlexKudrya\Adminix\Modules\List\ListField class instance as an argument to addField or addFields method of ListModule object.

Field Presentation

ListField supports the same presentation helpers as resource fields for table columns and inline-edit controls. These helpers only change server-rendered UI; they do not change query criteria, sorting, writable fields, or export behavior.

ListField::name('Customer') ->field('customer_name') ->editable() ->placeholder('Customer name') ->help('Shown below the column title') ->wideWidth() ->alignStart();

Available helpers:

  • placeholder($text) sets inline-edit input placeholders and async select search placeholders;

  • help($text) renders escaped helper text in the table header;

  • width('narrow'|'medium'|'wide'|'full') adds safe width classes to the table header and cells;

  • narrowWidth(), mediumWidth(), wideWidth(), and fullWidth() are named width shortcuts;

  • alignment('start'|'center'|'end') controls table header/cell alignment; left, middle, and right are normalized aliases;

  • alignStart(), alignCenter(), and alignEnd() are named alignment shortcuts.

Invalid width/alignment values are ignored. Use hiddenOnIndex(), hideable(), defaultHidden(), editable(), and exportable() for behavior; presentation helpers are not access-control tools.

Row details

Use ListRowDetails when a list needs a compact primary row plus expandable read-only metadata. Adminix renders one toggle column and a hidden detail row for every visible record. The detail panel is prepared from the same server-side list datasource, base criteria, active lens, filters, search, sorting, pagination, and optional relation scope used for the rendered table.

use AlexKudrya\Adminix\Modules\Detail\DetailField; use AlexKudrya\Adminix\Modules\List\ListRowDetails; ListModule::name('orders') ->dataSource(Order::class) ->rowDetails( ListRowDetails::make('Order details') ->columns(2) ->addFields( DetailField::make('Status', 'status')->badge('#754195'), DetailField::make('Total', 'total')->money('USD', 2), DetailField::make('Payload', 'metadata')->json(), DetailField::make('Receipt', 'receipt_url')->link() ) ) ->addFields(...);

ListRowDetails supports:

  • make($title = null)/title() for an optional detail heading;

  • columns(1..4) for the read-only field grid;

  • addField()/addFields() with DetailField or another ResourceField subclass;

  • expanded() to render all detail rows initially open, otherwise they are collapsed and toggled with JavaScript.

Row details do not add a write endpoint and do not trust browser-owned datasource, criteria, field names, or primary keys. Password fields are rendered without stored values, matching resource/detail password safety. Keep sensitive tenant, owner, credential, and internal audit columns out of row details unless they are intentionally visible to the admin user.

Badge / Status Field

Use badge() or status() when a list column should show a compact visual state instead of raw text. Badge fields are display-only: even on editable lists, ListFieldTypeEnum::BADGE is excluded from inline edit writes.

ListField::name('Status') ->field('status') ->status([ 'draft' => ['label' => 'Draft', 'color' => '#64748b'], 'published' => ['label' => 'Published', 'color' => '#16a34a'], 'failed' => ['label' => 'Failed', 'color' => '#dc2626'], ]);

badge('#754195') applies one color to all values. badgeMap() accepts the same map as status(). When a value is not mapped, Adminix renders the scalar value with the field default badge color.

Money / Currency Field

Use money($currency = 'USD', $decimals = 2) for amount columns that should render as tabular currency values. On editable lists, money fields remain writable number inputs and use a decimal step derived from $decimals.

ListField::name('Total') ->field('total') ->money('EUR', 2);

Result: read-only cells render values such as EUR 1,234.50; editable cells render a number input with step="0.01".

Color Field

Use color() for color values stored as CSS color strings, commonly hex values such as #754195. Read-only list cells render a swatch and the stored value; editable list cells render a native color picker.

ListField::name('Brand color') ->field('brand_color') ->color();

Slug Field

Use slug() for columns that store URL-friendly slugs. List slug fields render like scalar text and can still be sortable when the underlying database column supports it.

ListField::name('Slug') ->field('slug') ->slug() ->sortable();

If the list is editable and the field is marked editable(), Adminix renders a normal text input. Keep slug validation and uniqueness server-side in the resource or inline-edit validation rules.

Markdown Field

Use markdown() for columns that store markdown text. Read-only list cells render a compact safe preview: raw HTML is escaped, while simple markdown links, **strong**, *emphasis*, inline code, and line breaks are rendered. Editable list cells render a textarea and submit the raw markdown value.

ListField::name('Content') ->field('content_md') ->markdown() ->defaultHidden();

Markdown columns are usually long, so generated smart resources mark them defaultHidden() and do not make them sortable. Keep validation and content policy server-side.

JSON / Code Field

Use json() for JSON payload columns. Read-only list cells render a compact pretty-printed preview, and editable list cells render a monospace textarea with progressive JSON syntax feedback. The helper adds the Laravel json validation rule; if JavaScript is unavailable, inline edit still submits a normal textarea value to server validation.

ListField::name('Payload') ->field('payload') ->json() ->defaultHidden();

Generated smart resources mark JSON list columns defaultHidden() and do not make them sortable. Keep schema-specific validation in the consuming application.

Key-Value Field

Use keyValue() for object-like JSON columns such as metadata, settings, options, or attributes. Read-only list cells render compact key/value rows. Editable list cells render the same progressive key/value editor as resource forms and submit a single JSON object field.

ListField::name('Metadata') ->field('metadata') ->keyValue() ->defaultHidden();

The helper adds the Laravel json validation rule. Generated smart resources mark key-value list columns defaultHidden() and do not make them sortable.

Date Range Field

Use dateRange() for JSON values shaped like {"from":"2026-01-01","to":"2026-01-31"}. Read-only list cells render a compact date-range label, and editable list cells render the same progressive two-date editor as resource forms.

ListField::name('Booking window') ->field('booking_window') ->dateRange() ->defaultHidden();

The helper adds the Laravel json validation rule. Keep ordering and filtering on dedicated date columns when the database needs efficient range queries; this field is for displaying or editing a persisted range value.

Timezone Field

Use timezone() for columns that store IANA timezone identifiers. Read-only list cells render the stored identifier, and editable list cells render the same server-declared timezone select as resource forms.

ListField::name('Timezone') ->field('timezone') ->timezone() ->sortable();

The helper adds Laravel's timezone validation rule for editable list submissions. Use application validation when timezone changes must be restricted by tenant, user, or business context.

Tags Field

Use tags($separator = ',') for tag-list columns. Read-only list cells render chips. Editable list cells render a normal text input with a progressive chip preview and submit the separator-delimited string.

ListField::name('Tags') ->field('tags') ->tags() ->defaultHidden();

The formatter accepts separator-delimited strings, JSON array strings, and array values. Generated smart resources mark tag columns defaultHidden() and do not make them sortable.

Example:

use App\Models\User; use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\List\ListModule; ... $page = new AdminixPage(); ... $page->addModule( ListModule::name('users') ->title('USERS') ->dataSource(User::class) ->pagination(20) ->addFields( ListField::name('Avatar') ->field('avatar') ->type(ListFieldTypeEnum::IMAGE), ListField::name('Name') ->field('name') ->type(ListFieldTypeEnum::STRING) ->sortable() ->editable(), ListField::name('Role') ->field('role_id') ->type(ListFieldTypeEnum::SELECT) ->editable() ->src( InputSelectSrc::nameField('name') ->valueField('id') ->dataSource(Role::class) ) ->addValidationRules( 'integer', 'required', 'exists:'. Role::class.',id' ), ListField::name('Rating') ->field('rating') ->type(ListFieldTypeEnum::INTEGER) ->editable() ->sortable() ->addValidationRules( 'integer', 'required', 'min:0', ), ListField::name('Registration') ->field('created_at') ->type(ListFieldTypeEnum::DATETIME) ->sortable(), ListField::name('Administrator') ->field('is_admin') ->type(ListFieldTypeEnum::BOOLEAN), ListField::field('deleted_at') ->type(ListFieldTypeEnum::HIDDEN), ListField::field('id') ->type(ListFieldTypeEnum::HIDDEN), ) ) ...

ListField configurations

Method

Description

name

Title of the field displayed on the top of table (inside <th/> tag)

name('Role')

Required

type

Type of rendered field, can be provided only by AlexKudrya\Adminix\Modules\List\ListFieldTypeEnum Enum class

Available types for rendered field:

  • STRING

  • EMAIL

  • INTEGER

  • FLOAT

  • BOOLEAN

  • SELECT

  • DATE

  • DATETIME

  • HIDDEN

  • MARKDOWN

  • JSON

  • TAGS

  • KEY_VALUE

  • DATE_RANGE

  • TIMEZONE

  • TEXTAREA

It determines data format to render, and type of input for editable mode.

Example:

type(ListFieldTypeEnum::SELECT)

Required

field

Name of field in database or resource (if resource was provided).

field('role_id')

Required

sortable

Determines the sorting possibility for current field.

Can not be used to fields which provided by resource, and not exist in database table, or his name was modified.

By default, is not enabled.

sortable()

Optional

hideable

Allows the field to appear in the columnVisibility() menu. The column is visible by default until the user hides it in the browser.

hideable()

Optional

defaultHidden

Allows the field to appear in the columnVisibility() menu and hides it by default. The user can show it again from the list settings menu.

defaultHidden()

Optional

editable

Determines the editable possibility for current field.

Can not be used to fields which provided by resource, and not exist in database table, or his name was modified.

This will not be working if in List module editable mode is not enabled.

To working correctly requires primary key (usually it is "id" field) in this fields list (can be hidden type).

By default, is not enabled.

editable()

Optional

src

Required for fields with type SELECT. Need to display correct value from related table.

For example, users table has related table roles, and relation made by role_id field in users table. To display normal role name from roles table, not role_id from users table, you need to configure src correctly.

Argument can be only AlexKudrya\Adminix\Modules\InputSelectSrc class instance.

Example:

ListField::name('Role') ->field('role_id') ->type(ListFieldTypeEnum::SELECT) ->editable() ->src( InputSelectSrc::nameField('name') ->valueField('id') ->dataSource(Role::class) )

InputSelectSrc configuration:

Methods

Description

dataSource

Source of data for filed items, can be an Eloquent Model - \App\Models\Role::class or name of table in database rolesor public.roles

dataSource(\App\Models\Role::class)

nameField

Name of field in related table to be displayed

nameField('name')

valueField

Name of primary key field related to main table (usually it is "id")

valueField('id')

asyncSrc

Use asyncSrc() for editable SELECT columns with large option tables. Adminix renders a search input above the native <select>, fetches options with debounce, shows loading/empty states, and submits the selected value through the existing inline edit form.

Example:

use AlexKudrya\Adminix\Modules\AsyncInputSelectSrc; ListField::name('Author') ->field('author_id') ->type(ListFieldTypeEnum::SELECT) ->editable() ->asyncSrc( AsyncInputSelectSrc::dataSource(User::class) ->nameField('name') ->valueField('id') ->searchFields(['name', 'email']) ->criteria(['active' => true]) ->minLength(2) ->limit(20) ->placeholder('Search authors') );

Result: editable rows search remote options with GET /{adminix-prefix}/api/async-select/{page}/{module}/{field}?q=..., and selected row values are resolved with ?value=.... The endpoint accepts only server-configured datasource, criteria, search fields, and limits.

For read-only list cells, async fields render the stored value because Adminix intentionally does not eager-load labels for all rows. Use synchronous src() or a resource/data transform when a read-only list must display labels.

addSelectRecords

Required for fields with type SELECT as an alternative for src(). Required if src is empty. It is a list of options, where name() is a title of <option/>, and value()is a value of <option/>

Arguments can be only AlexKudrya\Adminix\Modules\SelectRecord class instances.

Example:

ListField::name('Role') ->field('role_id') ->type(ListFieldTypeEnum::SELECT) ->editable() ->addSelectRecords( SelectRecord::name('Admin')->value(1), SelectRecord::name('Manager')->value(2), SelectRecord::name('Seller')->value(3), SelectRecord::name('Guest')->value(4), ) ...

Column visibility

columnVisibility() adds a Columns section to the compact list settings dropdown for the current ListModule. Only fields marked with hideable() or defaultHidden() are included in that section. The list settings dropdown grows to its content height and only uses vertical scrolling when the menu would exceed the viewport. On narrower desktop viewports, the list settings button shifts left only when its screen position vertically overlaps the fixed shell notification bell. Column toggles, density options, reset, and CSV export actions share the same menu item sizing, spacing, rounded corners, and hover treatment. Column toggles are rendered as switch controls, matching boolean field controls elsewhere in Adminix.

ListModule::name('orders') ->title('Orders') ->dataSource(Order::class) ->columnVisibility() ->addFields( ListField::name('Number') ->field('number') ->sortable(), ListField::name('Customer') ->field('customer_email') ->hideable(), ListField::name('Internal note') ->field('internal_note') ->defaultHidden(), ListField::field('id') ->type(ListFieldTypeEnum::HIDDEN) );

Result: Adminix shows a gear-icon settings button as a root-level absolute control aligned to the list title area. The control does not reserve toolbar or filter space; when a list has no title, it stays inside the list root without adding an empty row. The Customer column is visible by default and can be hidden by the user. The Internal note column is hidden by default and can be shown from the same settings menu. The hidden id field and service columns for inline edit or row actions are not controlled by column visibility.

Column visibility is a browser-only presentation setting. It is stored in local storage by list name and does not change request keys, datasource, criteria, filters, sorting, row actions, authorization, or export scope. For server-side list visibility, use ListField::hiddenOnIndex()/hideOnIndex(). Hidden-on-index fields are not rendered in the table and are not writable through inline edit.

Density and sticky table controls

densitySwitcher(), stickyHeader(), and stickyActions() are opt-in presentation helpers for wide or frequently used tables.

ListModule::name('orders') ->title('Orders') ->dataSource(Order::class) ->densitySwitcher() ->stickyHeader() ->stickyActions() ->addFields(...) ->addActions( LinkModule::name('details') ->title('Details') ->uri('orders.show') ->params(['record:id']), ModalTogglerModule::name('edit_order') ->modalName('order_modal') ->params(['record:id']) );

Result: Adminix renders Comfortable and Compact density choices inside the gear-icon list settings menu. The selected density is stored in browser local storage by list name. Compact density reduces table cell padding plus inline row controls such as editable inputs, selects, row action buttons, switches, date-range/key-value editors, async selects, and row images. Inline controls use a 32px minimum height, row images cap at 38px, cells align content vertically in the middle, and action button icons keep the normal UI-kit gap from text. stickyHeader() keeps table headers visible inside the scroll container. stickyActions() keeps the existing final service column visible while the table fits the available width. When a list table is wider than the available viewport, Adminix preserves the table's content width, moves the service column into the horizontal scroll flow, and uses horizontal scrolling instead of compressing or overlapping right-side columns into data cells.

These controls do not create a new action layer. Existing addAction()/addActions() links, non-GET forms, confirm prompts, tooltips, modal togglers, and record:*/param:* route parameters continue to render through the same row action contract. If the list also uses rowActionsDropdown(), stickyActions() keeps the dropdown trigger in the same service column.

CSV export

exportCsv() adds an Export CSV action to the list settings menu for the current ListModule. CSV export is disabled by default and must be enabled per list.

ListModule::name('orders') ->title('Orders') ->dataSource(Order::class) ->criteria([ ['tenant_id', '=', 'param:0'], ]) ->exportCsv(limit: 5000) ->addFields( ListField::name('Number') ->field('number') ->sortable(), ListField::name('Status') ->field('status'), ListField::name('Internal ID') ->field('id') ->type(ListFieldTypeEnum::HIDDEN), ListField::name('Tenant') ->field('tenant_id') ->type(ListFieldTypeEnum::HIDDEN) ->exportable() );

Result: Adminix shows an Export CSV action inside the gear-icon list settings menu. The endpoint applies the same server-side datasource, criteria, active lens, filters, search, and sorting as the list. The current pagination page is ignored, and export rows are capped by the configured limit. The default limit is 10000.

The browser cannot choose a datasource or arbitrary columns for CSV export. Adminix signs the current page params when rendering the export link so param:* criteria use the same route context as the visible list. ListFieldTypeEnum::HIDDEN fields are excluded by default. Use ListField::exportable() only for hidden fields that are safe to include in the CSV. Fields hidden with hiddenOnIndex() are also excluded unless they are explicitly marked exportable(). Row actions, inline edit controls, service columns, and UI-only column visibility are not exported.

Bulk actions

Bulk actions are opt-in server-side actions for selected rows in a ListModule. They render a checkbox column, Select all current page checkbox, action dropdown, selected count, and submit button above the table.

use AlexKudrya\Adminix\Modules\List\BulkAction; use AlexKudrya\Adminix\Modules\List\BulkActionHandlerInterface; use AlexKudrya\Adminix\Modules\List\BulkActionRequest; use AlexKudrya\Adminix\Modules\List\BulkActionResult; use AlexKudrya\Adminix\Modules\List\ListField; use AlexKudrya\Adminix\Modules\List\ListFieldTypeEnum; use AlexKudrya\Adminix\Modules\List\ListModule; use AlexKudrya\Adminix\Actions\ActionField; use AlexKudrya\Adminix\Actions\ActionFieldTypeEnum; use AlexKudrya\Adminix\Modules\SelectRecord; ListModule::name('orders') ->title('Orders') ->dataSource(Order::class) ->criteria([ ['tenant_id', '=', 'param:0'], ]) ->primaryKey('id') ->addFields( ListField::name('ID') ->field('id') ->type(ListFieldTypeEnum::HIDDEN), ListField::name('Number') ->field('number'), ListField::name('Status') ->field('status') ) ->addBulkAction( BulkAction::make('mark_paid') ->title('Mark paid') ->icon('bi bi-check2') ->confirm('Mark selected orders as paid?') ->batchLimit(500) ->handler(MarkOrdersPaidAction::class) ); final class MarkOrdersPaidAction implements BulkActionHandlerInterface { public function handle(BulkActionRequest $request): BulkActionResult { $request->query()->update([ 'status' => 'paid', ]); return BulkActionResult::success(count($request->selectedIds()) . ' orders updated.'); } }

Result: Adminix shows bulk controls above the list. The button stays disabled until the user selects at least one current-page row and one configured action. When confirm() is configured, the browser shows that confirmation before submitting. The web endpoint redirects back with a success or error toast, or returns a direct Response when the handler returns one.

BulkAction settings:

  • name() is the stable server-side action key submitted by the browser.

  • title() is the dropdown label.

  • icon() stores an optional Bootstrap icon class for package consumers and future renderers.

  • tooltip() stores optional helper text for package consumers and future renderers.

  • color() stores an optional ColorsEnum value or CSS color string.

  • destructive() marks dangerous actions for custom renderers and future UI states.

  • confirm() sets an optional submit confirmation message.

  • criteria() stores optional action visibility criteria metadata; execution still uses the selected row scope.

  • addField()/addFields() declare input fields shown before the selected bulk action is submitted.

  • handler() accepts a callable, object, or class string. Implement BulkActionHandlerInterface for reusable actions.

  • authorizeUsing()/authorization() accepts a boolean, callable, object with authorize(), or class string.

  • batchLimit() caps selected scalar IDs before the handler runs. Default is 1000.

  • queued('Message') dispatches the handler through Laravel queues after the normal server-side scope and authorization checks.

  • progressTrigger() starts a matching ProgressBarModule trigger when the selected action is submitted.

  • onConnection() and onQueue() optionally select the Laravel queue transport for queued bulk actions.

  • actionMetadata() returns the shared Actions metadata DTO.

BulkActionRequest gives handlers:

  • module() and action() from server-side configuration;

  • requestedIds() from the request after scalar normalization;

  • selectedIds() after applying the current list scope;

  • query() already scoped to selected records;

  • primaryKey() from the list module;

  • httpRequest() for request/session context when needed.

  • fields() and field($name, $default = null) for server-declared action field values.

Action fields are documented in Actions. They are submitted as adminix_action_fields[...], but Adminix only passes keys declared on the selected server-side BulkAction to the handler.

Handlers can return:

  • BulkActionResult::success('Message');

  • BulkActionResult::error('Message');

  • BulkActionResult::validation(['field' => ['Message']]);

  • BulkActionResult::redirect('/adminix/orders');

  • BulkActionResult::openInNewTab('/adminix/orders/export.csv');

  • BulkActionResult::modal('Title', 'Body');

  • BulkActionResult::download($response) or a Symfony/Laravel Response for downloadable/custom responses.

Typed action responses are documented in Actions. Queued actions are documented in Actions.

The endpoint resolves page, module, relation context, and action from server-side module configuration. The browser submits only selected IDs and action name. Datasource, primary key, criteria, active lens, filters, search, sorting, relation parent scope, and page params are resolved server-side. IDs outside the current criteria/search/filter/relation scope are ignored; if no selected ID remains in scope, the request fails with a controlled validation error. After a handler returns a normalized result, Adminix dispatches BulkActionExecuted and passes the scope-filtered selected IDs in audit metadata. See Audit for recorder and listener examples.

Bulk actions do not replace row actions. Existing addAction()/addActions() links, non-GET row forms, modal togglers, confirm prompts, tooltips, and record:* params remain the row action contract.

Searching

Determines possibility to make full-text search in source table.

Example:

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\List\ListSearch; $page = new AdminixPage(); ... $page->addModule( ListModule... ->search( ListSearch::searchFields(['name', 'email']) ->placeholder('Search users') ) ) ...

Method

Description

searchFields

An array of fields which involved in the search process. The more fields, the slower but more accurate the search. Every field must be existed in main database table

searchFields(['name', 'email'])

Required

placeholder

A placeholder for Search <input/>

placeholder('Search users')

Optional

Filters

Add filters to the top of the module, near to search input. Provides the ability to filter the list by specific fields.

There are several types of filters available:

ListFilter

Basic filter - <select/> input with defined options

Example:

1 usage variant - get records for filter from DB table by Eloquent model or table name, and took nameField as displayable name and valueField as value for filtering

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\List\ListFilter; $page = new AdminixPage(); ... $page->addModule( ListModule... ->addFilters( ListFilter::field('role_id') ->name('Role') ->src( InputSelectSrc::nameField('name') ->valueField('id') ->dataSource(\App\Models\Role::class) ), ) ) ...

Or 2 usage variant - get records for filter from DB table by Eloquent model or table name by SELECT DISTINCT ... query

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\List\ListFilter; $page = new AdminixPage(); ... $page->addModule( ListModule... ->addFilters( ListFilter::field('role') ->name('Role') ->distinct('role', \App\Models\User::class), ) ) ...

Or 3 usage variant - set records for filter manually as list of ListFilterRecord objects

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\List\ListFilter; $page = new AdminixPage(); ... $page->addModule( ListModule... ->addFilters( ListFilter::field('role_id') ->name('Role') ->addFilterRecords( ListFilterRecord::name('Client')->value(1), ListFilterRecord::name('Guest')->value(2), ListFilterRecord::name('Manager')->value(3), ListFilterRecord::name('Admin')->value(4), ) ) ) ...

Method

Description

name

Title of the filter

name('Role')

Required

field

Name of the field used for filtering. Field must be existed in base database table

field('role_id')

Required

src

Required if filter_records is empty. Has a format similar to select field src directive:

src( InputSelectSrc::nameField('name') ->valueField('id') ->dataSource(\App\Models\Role::class) ),

setting

Description

dataSource

Source of data for filed items, can be an Eloquent Model - \App\Models\Role::class or name of table in database rolesor public.roles

nameField

Name of the field witch used as a title of <option/>

valueField

Name of the field witch used as a value of <option/> (usually it is "id")

Required if no filterRecords() and no distinct()

distinct

Field and table for `SELECT DISTINCT` selection

distinct('role', \App\Models\User::class),

**Required** if no **src()** and no **filterRecords()**

filterRecords

Required if src is empty. It is an array of options, where name is a title of <option/>, and valueis a value of <option/>

addFilterRecords( ListFilterRecord::name('Client')->value(1), ListFilterRecord::name('Guest')->value(2), ListFilterRecord::name('Manager')->value(3), ListFilterRecord::name('Admin')->value(4), )

Required if no src() and no distinct()

ListDateFilter

Date filter - allows you to select records within a selected date.

Example:

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\List\ListDateFilter; $page = new AdminixPage(); ... $page->addModule( ListModule... ->addFilters( ListDateFilter::field('created_at') ->name('Registration date') ) ) ...

Method

Description

field

Name of the field used for filtering. Field must have timestamp, date or datetime format.

field('created_at')

Required

name

Title of the filter

name('Registration date')

Required

ListDateRangeFilter

Date range filter - allows you to select records within a date range.

Example:

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\List\ListDateRangeFilter; $page = new AdminixPage(); ... $page->addModule( ListModule... ->addFilters( ListDateRangeFilter::field('created_at') ->name('Registration date') ->withTime() ) ) ...

Method

Description

field

Name of the field used for filtering. Field must have timestamp, date or datetime format.

field('created_at')

Required

name

Title of the filter

name('Registration date')

Required

withTime

Determines whether the filter will filter by time or only by dates.

By default, filter only by date, without time.

withTime()

Optional

filterFrom

Define "From" input. If set false, "From" datepicker will not be displayed.

By default, it is enabled.

filterFrom(false)

Optional

filterTo

Define "To" input. If set false, "To" datepicker will not be displayed.

By default, it is enabled.

filterTo(false)

Optional

Reset controls

resetControls() adds a Reset view action to the list settings menu for the current ListModule. It is disabled until the current URL or browser storage contains state for that list.

ListModule::name('orders') ->title('Orders') ->dataSource(Order::class) ->resetControls() ->search( ListSearch::searchFields(['number', 'customer_email']) ->placeholder('Search orders') ) ->addFilters(...) ->addLenses(...) ->addFields(...);

Result: when the URL contains keys such as search-orders, filter-orders-status, sort-orders-created_at, lens-orders, or page, Adminix shows an enabled Reset view action inside the gear-icon list settings menu. The same action is enabled when browser-only view state exists for the list, such as hidden/shown columns or compact density. Clicking it returns to the same page without current-list URL state and clears current-list browser view state. Unrelated query parameters and another list module's view state are preserved.

This is a presentation and URL-state convenience only. It does not create a new server-side action endpoint and does not change list filters, row actions, datasource, or authorization behavior.

Mobile behavior

ListModule keeps the same PHP configuration and request contract on mobile. Search, lenses, filters, sorting, pagination, editable rows, row actions, and modal togglers still use the same module name and server-side configuration.

Example configuration:

ListModule::name('orders') ->title('Orders') ->dataSource(Order::class) ->search( ListSearch::searchFields(['number', 'customer_email']) ->placeholder('Search orders') ) ->addFilters( ListFilter::field('status') ->name('Status') ->addFilterRecords( ListFilterRecord::name('Paid')->value('paid'), ListFilterRecord::name('Refunded')->value('refunded') ), ListDateRangeFilter::field('created_at') ->name('Created') ) ->addActions( AdminixLinkModule::name('details') ->title('Details') ->uri(OrderPage::URI) ->params(['record:id']) ) ->addFields(...);

Result:

  • desktop renders filters inline above the table;

  • narrow screens show a Filters button with an active-filter count;

  • the button opens a drawer containing the same ListFilter, ListDateFilter, and ListDateRangeFilter controls;

  • changing a filter still writes the same filter-{moduleName}-{field} query key and resets pagination;

  • wide tables scroll horizontally inside the table area, not across the whole Adminix shell;

  • row actions remain the existing buttons/forms/modal togglers, including route params, CSRF methods, confirm text, icons, and tooltips.

The mobile drawer is a presentation wrapper only. Do not add browser-owned datasource, action, or filter metadata; continue to configure lists from PHP classes.

Actions

"Actions" is an array of control buttons for every single record, to do some actions, such as "open", "edit", "delete", or wherever else you need.

Example:

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\Link\AdminixLinkModule; use AlexKudrya\Adminix\Modules\Link\LinkModule; use AlexKudrya\Adminix\Enums\HttpMethodsEnum; $page = new AdminixPage(); ... $page->addModule( ListModule... ->addActions( AdminixLinkModule::name('edit') ->title('EDIT') ->icon('bi bi-pencil') ->uri(UserPage::URI) ->params(['record:id']), LinkModule::name('delete') ->title('BAN') ->icon('bi bi-person-fill-slash') ->uri('ban_user') ->method(HttpMethodsEnum::POST) ->params(['record:id']) ->criteria([ ['deleted_at', '==', null] ]), LinkModule::name('restore') ->title('UNBAN') ->icon('bi bi-person-fill-up') ->uri('unban_user') ->method(HttpMethodsEnum::POST) ->params(['record:id']) ->criteria([ ['deleted_at', '!=', null] ]), ) ) ...

To add Action buttons to List module you need paste AlexKudrya\Adminix\Modules\Link\AdminixLinkModule or AlexKudrya\Adminix\Modules\Link\LinkModule class instances as an argument to addAction or addActions method of AdminixPage object.

Action buttons syntax is similar to Link module

By default, Adminix renders row actions inline in the final service column. For dense tables with many row controls, call rowActionsDropdown() on the same ListModule to render one compact vertical three-dots button per row. Clicking it opens a small contextual dropdown next to the trigger and shows the same configured actions inside the menu.

ListModule::name('users') ->dataSource(User::class) ->rowActionsDropdown() ->addFields(...) ->addActions( AdminixLinkModule::name('edit') ->title('Edit') ->icon('bi bi-pencil') ->uri(UserPage::URI) ->params(['record:id']), LinkModule::name('ban') ->title('Ban') ->icon('bi bi-person-fill-slash') ->uri('ban_user') ->method(HttpMethodsEnum::POST) ->params(['record:id']) );

Result: every row keeps a single bi-three-dots-vertical trigger in the action column. The dropdown contains the existing GET links, POST/PUT/PATCH/DELETE forms with CSRF and confirm prompts, and modal togglers. If an action has an icon but no title, the dropdown uses the action name() as a text label so the menu remains readable. Rows where criteria() hides all actions still render an empty service cell to keep the table columns aligned.

rowActionsDropdown() is presentation-only. It does not change action authorization, criteria evaluation, route parameter substitution, signed modal relation context, request payloads, datasource, or persistence behavior.

Method

Description

name

Title which will be displayed on the button

name('EDIT')

Optional

uri

In case AdminixLinkModule uri means the uri directive of page which defined in Adminix config file. In this case better to use URI constant from target page provider class.

uri(UserPage::URI)

In case LinkModule uri means the name of any route defined in router of your Laravel application. Just copy route name from router.

uri('edit_user')

Required

icon

Icon class name from Bootsrap icons

Example: to generate in the Link an icon <i class="bi bi-people-fill"></i> you need paste here bi bi-people-fill class name

icon('bi bi-people-fill')

Optional

method

Type of HTTP request, can be provided only by AlexKudrya\Adminix\Enums\HttpMethodsEnum Enum class

In case AdminixLinkModule method can be only GET so it is redundant.

In case LinkModule method must be match to the route defined in uri directive.

By default, it is equal to HttpMethodsEnum::GET

method(HttpMethodsEnum::POST)

Required if not GET

params

Technically it is optional directive, but action without params makes it pointless, so it is make it required.

It is list of parameters which you added to your action (usually it is "id"). When record:id, means that id of current record will be the parameter. By the way, for this purpose, if you not display id field i your list, you need add it to fields directive, if you do not want to display it you may add this field with HIDDEN type.

Parameters adds to your link like this: /parameter 1/parameter 2...

Example:

params(['record:id'])

For record with id = 123 action link will be https://example/uri/123

Required

criteria

Determines display or not this action button for current record. For example if you need display action button only for users without admin status, you can do it like this:

criteria([ ['is_admin', '==', false] ])

or

criteria([ ['deleted_at', '!=', null] ])

Action visibility criteria are evaluated against the rendered list row, not the database query builder. For row actions this directive intentionally supports only == and !=, including null checks.

Optional

Usually, in the admin panels, lists have the ability to add new records, and the New resource module is used for this. In order to display a link to a page with such a module in the correct place in the "list" module, there is this directive

Format is similar to Link module or Actions

Example:

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\Link\AdminixLinkModule; $page = new AdminixPage(); ... $page->addModule( ListModule... ->newItemLink( AdminixLinkModule::name('new_user_btn') ->title('NEW USER') ->icon('bi bi-person-fill-add') ->uri(NewUserPage::URI) ) ) ...

or

use AlexKudrya\Adminix\AdminixPage; use AlexKudrya\Adminix\Modules\Link\AdminixLinkModule; $page = new AdminixPage(); ... $page->addModule( ListModule... ->newItemLink( ModalTogglerModule::name('new_user_btn') ->title('NEW USER') ->icon('bi bi-person-fill-add') ->modalName('new_user_modal') ) ) ...

Appearance examples

Here is example of List without editable mode:

image.png

Here is example of List with editable mode:

image.png
Last modified: 25 June 2026