Admin Grid/Form Components
Learn how to create and modify admin grids and forms using UI Components to manage custom entities in the Magento admin panel.
Admin Grid/Form Components Overview
Admin Grids Overview
A standard admin grid displays data from a database table in a tabular format with features like sorting, filtering, pagination, and mass actions.
Steps to Create an Admin Grid
Required Steps
- Create a new controller in
adminhtml - Modify layout to include the UiComponent's configuration
- Create a listing (grid) component XML file
- Create/configure the DataSource for the grid
- Create controllers for mass actions
- Optionally - Create a controller for inline editing
Step 1: Create Admin Controller
<?php
namespace Vendor\Module\Controller\Adminhtml\Entity;
use Magento\Backend\App\Action;
use Magento\Framework\View\Result\PageFactory;
class Index extends Action
{
const ADMIN_RESOURCE = 'Vendor_Module::entity';
protected $resultPageFactory;
public function __construct(
Action\Context $context,
PageFactory $resultPageFactory
) {
parent::__construct($context);
$this->resultPageFactory = $resultPageFactory;
}
public function execute()
{
$resultPage = $this->resultPageFactory->create();
$resultPage->setActiveMenu('Vendor_Module::entity');
$resultPage->getConfig()->getTitle()->prepend(__('Manage Entities'));
return $resultPage;
}
}
Step 2: Layout XML Declaration
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<update handle="styles"/>
<body>
<referenceContainer name="content">
<uiComponent name="entity_listing"/>
</referenceContainer>
</body>
</page>
<uiComponent name="entity_listing"/> references the UI Component XML file.
Step 3: Listing (Grid) Component XML
<?xml version="1.0"?>
<listing xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">
entity_listing.entity_listing_data_source
</item>
</item>
</argument>
<dataSource name="entity_listing_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">
Magento\Framework\View\Element\UiComponent\DataProvider\DataProvider
</argument>
<argument name="name" xsi:type="string">entity_listing_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">entity_id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
</argument>
</dataSource>
<columns name="entity_columns">
<column name="entity_id">
<settings>
<label translate="true">ID</label>
</settings>
</column>
<column name="title">
<settings>
<filter>text</filter>
<label translate="true">Title</label>
</settings>
</column>
</columns>
</listing>
Step 4: DataSource Configuration (di.xml)
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<type name="Magento\Framework\View\Element\UiComponent\DataProvider\CollectionFactory">
<arguments>
<argument name="collections" xsi:type="array">
<item name="entity_listing_data_source" xsi:type="string">
Vendor\Module\Model\ResourceModel\Entity\Grid\Collection
</item>
</argument>
</arguments>
</type>
<type name="Vendor\Module\Model\ResourceModel\Entity\Grid\Collection">
<arguments>
<argument name="mainTable" xsi:type="string">entity_table</argument>
<argument name="eventPrefix" xsi:type="string">entity_grid_collection</argument>
<argument name="eventObject" xsi:type="string">entity_grid_collection</argument>
<argument name="resourceModel" xsi:type="string">
Vendor\Module\Model\ResourceModel\Entity
</argument>
</arguments>
</type>
</config>
di.xml must match the dataSource name in the UI Component XML.
Grid Collection with SearchResultInterface
A separate Grid Collection is created to implement SearchResultInterface. You may use the standard collection as well if implementing this interface.
<?php
namespace Vendor\Module\Model\ResourceModel\Entity\Grid;
use Magento\Framework\Api\Search\SearchResultInterface;
use Vendor\Module\Model\ResourceModel\Entity\Collection as EntityCollection;
class Collection extends EntityCollection implements SearchResultInterface
{
protected $aggregations;
public function getAggregations() { return $this->aggregations; }
public function setAggregations($aggregations) { $this->aggregations = $aggregations; }
public function getSearchCriteria() { return null; }
public function setSearchCriteria(\Magento\Framework\Api\SearchCriteriaInterface $searchCriteria = null) { return $this; }
public function getTotalCount() { return $this->getSize(); }
public function setTotalCount($totalCount) { return $this; }
public function setItems(array $items = null) { return $this; }
}
SearchResultInterface.
Mass Actions
Mass actions allow users to perform operations on multiple grid items at once.
Configuring Mass Actions
<listingToolbar name="listing_top">
<massaction name="listing_massaction">
<action name="delete">
<settings>
<confirm>
<message translate="true">Are you sure you want to delete selected items?</message>
<title translate="true">Delete items</title>
</confirm>
<url path="*/*/massDelete"/>
<type>delete</type>
<label translate="true">Delete</label>
</settings>
</action>
<action name="disable">
<settings>
<url path="*/*/massDisable"/>
<type>disable</type>
<label translate="true">Disable</label>
</settings>
</action>
<action name="enable">
<settings>
<url path="*/*/massEnable"/>
<type>enable</type>
<label translate="true">Enable</label>
</settings>
</action>
<!-- Edit Action (triggers JS module) -->
<action name="edit">
<settings>
<callback>
<target>editSelected</target>
<provider>entity_listing.entity_listing.entity_columns_editor</provider>
</callback>
<type>edit</type>
<label translate="true">Edit</label>
</settings>
</action>
</massaction>
</listingToolbar>
Mass Action Controller Example
<?php
namespace Vendor\Module\Controller\Adminhtml\Entity;
use Magento\Backend\App\Action;
use Magento\Framework\Controller\ResultFactory;
use Magento\Ui\Component\MassAction\Filter;
use Vendor\Module\Model\ResourceModel\Entity\CollectionFactory;
class MassDelete extends Action
{
const ADMIN_RESOURCE = 'Vendor_Module::entity_delete';
protected $filter;
protected $collectionFactory;
public function __construct(
Action\Context $context,
Filter $filter,
CollectionFactory $collectionFactory
) {
$this->filter = $filter;
$this->collectionFactory = $collectionFactory;
parent::__construct($context);
}
public function execute()
{
$collection = $this->filter->getCollection($this->collectionFactory->create());
$collectionSize = $collection->getSize();
foreach ($collection as $item) {
$item->delete();
}
$this->messageManager->addSuccessMessage(
__('A total of %1 record(s) have been deleted.', $collectionSize)
);
return $this->resultFactory->create(ResultFactory::TYPE_REDIRECT)->setPath('*/*/');
}
}
Magento\Cms\Controller\Adminhtml\Page\MassDelete and Magento\Cms\Controller\Adminhtml\Page\MassEnable.
Inline Editing
Inline editing allows users to edit grid data directly without opening a separate form.
Steps for Inline Editing
- Configure the
editorConfignode in the listing XML file - Configure the editor for each field
- Create a controller to save the result
1. Configure editorConfig
<columns name="entity_columns">
<settings>
<editorConfig>
<param name="clientConfig" xsi:type="array">
<item name="saveUrl" xsi:type="url" path="*/*/inlineEdit"/>
<item name="validateBeforeSave" xsi:type="boolean">true</item>
</param>
<param name="indexField" xsi:type="string">entity_id</param>
<param name="enabled" xsi:type="boolean">true</param>
<param name="selectProvider" xsi:type="string">${ $.columnsProvider }.ids</param>
</editorConfig>
</settings>
</columns>
2. Configure Editor for Each Field
<column name="title">
<settings>
<filter>text</filter>
<editor>
<validation>
<rule name="required-entry" xsi:type="boolean">true</rule>
</validation>
<editorType>text</editorType>
</editor>
<label translate="true">Title</label>
</settings>
</column>
3. InlineEdit Controller
<?php
namespace Vendor\Module\Controller\Adminhtml\Entity;
use Magento\Backend\App\Action;
use Magento\Framework\Controller\Result\JsonFactory;
class InlineEdit extends Action
{
const ADMIN_RESOURCE = 'Vendor_Module::entity_save';
protected $jsonFactory;
protected $entityFactory;
public function execute()
{
$resultJson = $this->jsonFactory->create();
$error = false;
$messages = [];
if ($this->getRequest()->getParam('isAjax')) {
$postItems = $this->getRequest()->getParam('items', []);
foreach (array_keys($postItems) as $entityId) {
$entity = $this->entityFactory->create()->load($entityId);
try {
$entity->setData(array_merge($entity->getData(), $postItems[$entityId]));
$entity->save();
} catch (\Exception $e) {
$messages[] = __('[ID: %1] %2', $entity->getId(), $e->getMessage());
$error = true;
}
}
}
return $resultJson->setData(['messages' => $messages, 'error' => $error]);
}
}
Magento\Cms\Controller\Adminhtml\Page\InlineEdit.
Admin Forms
Admin forms follow a similar pattern to grids but are used for creating and editing individual records.
Steps to Create an Admin Form
- Create controllers for form display, edit, save, and delete actions
- May need additional controllers for file uploading
- Modify layout to include UiComponent's configuration
- Create form UI component XML file
- Create/configure DataSource for the form
Magento/Cms/Controller/Adminhtml/Page/ for complete examples.
Form Layout XML
<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<update handle="styles"/>
<body>
<referenceContainer name="content">
<uiComponent name="entity_form"/>
</referenceContainer>
</body>
</page>
Form UI Component XML
<?xml version="1.0"?>
<form xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Ui:etc/ui_configuration.xsd">
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">entity_form.entity_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Entity Information</item>
</argument>
<dataSource name="entity_form_data_source">
<dataProvider class="Vendor\Module\Model\Entity\DataProvider" name="entity_form_data_source">
<settings>
<requestFieldName>id</requestFieldName>
<primaryFieldName>entity_id</primaryFieldName>
</settings>
</dataProvider>
</dataSource>
<fieldset name="general">
<settings>
<label translate="true">General Information</label>
</settings>
<field name="entity_id" formElement="input">
<settings>
<dataType>text</dataType>
<visible>false</visible>
</settings>
</field>
<field name="title" formElement="input">
<settings>
<validation>
<rule name="required-entry" xsi:type="boolean">true</rule>
</validation>
<dataType>text</dataType>
<label translate="true">Title</label>
</settings>
</field>
<field name="is_active" formElement="checkbox">
<settings>
<dataType>boolean</dataType>
<label translate="true">Is Active</label>
</settings>
<formElements>
<checkbox>
<settings>
<valueMap>
<map name="false" xsi:type="string">0</map>
<map name="true" xsi:type="string">1</map>
</valueMap>
<prefer>toggle</prefer>
</settings>
</checkbox>
</formElements>
</field>
</fieldset>
</form>
Key Components Summary
| Component | Purpose | Location |
|---|---|---|
| Controller | Handle requests, load data, return response | Controller/Adminhtml/Entity/ |
| Layout XML | Define page structure, reference UI Component | view/adminhtml/layout/ |
| UI Component XML | Configure grid/form structure, columns, fields | view/adminhtml/ui_component/ |
| DataSource (di.xml) | Configure collection for grid/form data | etc/di.xml |
| Grid Collection | Fetch and filter data (implements SearchResultInterface) | Model/ResourceModel/Entity/Grid/ |
| Mass Action Controllers | Handle bulk operations (delete, enable, disable) | Controller/Adminhtml/Entity/Mass* |
| InlineEdit Controller | Handle inline grid editing | Controller/Adminhtml/Entity/InlineEdit |
| DataProvider | Provide form data | Model/Entity/DataProvider.php |
Quick Reference: Grids vs Forms
Admin Grids
- Display multiple records in table format
- Use
<listing>root element - Grid Collection implements
SearchResultInterface - Support mass actions
- Optional inline editing
- Filtering, sorting, pagination built-in
Admin Forms
- Edit single record
- Use
<form>root element - DataProvider fetches form data
- Controllers: New, Edit, Save, Delete
- May need file upload controllers
- Field validation and dependencies
Exam Tips
Key Points to Remember
- 6 steps to create a grid: Controller, Layout, UI Component XML, DataSource, Mass Actions, Inline Editing (optional)
- Grid collections implement
SearchResultInterface - DataSource name in di.xml must match UI Component XML
- Mass actions configured in
listing/listingToolbar/massaction/actionnodes - Some mass actions trigger JS modules instead of immediate requests
- Inline editing requires: editorConfig, field editor config, InlineEdit controller
- Forms follow similar pattern to grids with different UI Component structure
- Form controllers handle CRUD operations: New, Edit, Save, Delete
- Layout XML is the same for both grids and forms - just reference the UI Component
- Real examples:
Magento_Cmsmodule for CMS pages