Here we learn how to add or create a UI-Select field using the block method on the Admin form.
Let’s start step by step.
You must have installed Magento 2 custom Module on which you are going to implement this.
Step 1: We need to create the layout file to define the admin form in view/adminhtml/layout/webkulblog_account_edit.xml :
<?xml version="1.0"?>
<!--
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
-->
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="admin-2columns-left" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<update handle="styles"/>
<update handle="editor"/>
<body>
<referenceBlock name="menu">
<action method="setActive">
<argument name="itemId" xsi:type="string">
Webkul_Custom:webkulblog
</argument>
</action>
</referenceBlock>
<referenceBlock name="page.title">
<action method="setTitleClass">
<argument name="class" xsi:type="string">
complex
</argument>
</action>
</referenceBlock>
</body>
</page>
Step 2: Create the block file, Webkul\Custom\Block\Adminhtml\Account\Edit.php
<?php
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
namespace Webkul\Custom\Block\Adminhtml\Account;
class Edit extends \Magento\Backend\Block\Widget\Form\Container
{
/**
* Initialize
*
* @return void
*/
protected function _construct()
{
$this->_objectId = 'entity_id';
$this->_blockGroup = 'Webkul_Custom';
$this->_controller = 'adminhtml_account';
parent::_construct();
if ($this->_isAllowedAction('Webkul_Custom::accountedit')) {
$this->buttonList->update('save', 'label', __('Save Account'));
} else {
$this->buttonList->remove('save');
}
$this->buttonList->remove('delete');
$this->buttonList->remove('reset');
}
/**
* Retrieve text for header element depending on loaded Group
*
* @return \Magento\Framework\Phrase
*/
public function getHeaderText()
{
return __('New Blog Account');
}
/**
* Check permission for passed action
*
* @param string $resourceId
* @return bool
*/
protected function _isAllowedAction($resourceId)
{
return $this->_authorization->isAllowed($resourceId);
}
}
Step 3: Create the block file, Webkul\Custom\Block\Adminhtml\Account\Edit\Tabs.php
<?php
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
namespace Webkul\Custom\Block\Adminhtml\Account\Edit;
class Tabs extends \Magento\Backend\Block\Widget\Tabs
{
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Json\EncoderInterface $jsonEncoder
* @param \Magento\Backend\Model\Auth\Session $authSession
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Json\EncoderInterface $jsonEncoder,
\Magento\Backend\Model\Auth\Session $authSession,
array $data = []
) {
parent::__construct($context, $jsonEncoder, $authSession, $data);
}
/**
* Construct
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->setId('blog_account_tab');
$this->setDestElementId('edit_form');
$this->setTitle(__('Blog Account Information'));
}
/**
* Prepare Layout
*
* @return $this
*/
protected function _prepareLayout()
{
$block = \Webkul\Custom\Block\Adminhtml\Account\Edit\Tab\BlogAccount::class;
$this->addTab(
'blog_account_info',
[
'label' => __('Blog Account'),
'content' => $this->getLayout()->createBlock($block, 'blog_account_info')->toHtml()
]
);
return parent::_prepareLayout();
}
}
Step 4: Create the block file, Webkul\Custom\Block\Adminhtml\Account\Edit\Tab\BlogAccount.php
<?php
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
namespace Webkul\Custom\Block\Adminhtml\Account\Edit\Tab;
use Magento\Backend\Block\Widget\Form\Generic;
use Magento\Backend\Block\Widget\Tab\TabInterface;
use Webkul\Custom\Block\Adminhtml\Widget\Form\Element\FilterSelect;
class BlogAccount extends Generic implements TabInterface
{
/**
* @param \Magento\Backend\Block\Template\Context $context
* @param \Magento\Framework\Registry $registry
* @param \Magento\Framework\Data\FormFactory $formFactory
* @param array $data
*/
public function __construct(
\Magento\Backend\Block\Template\Context $context,
\Magento\Framework\Registry $registry,
\Magento\Framework\Data\FormFactory $formFactory,
array $data = []
) {
parent::__construct($context, $registry, $formFactory, $data);
}
/**
* Prepare form
*
* @return $this
*/
protected function _prepareForm()
{
$model = $this->_coreRegistry->registry('business_list_model');
$form = $this->_formFactory->create();
$fieldset = $form->addFieldset(
'base_fieldset',
['legend' => __('Blog Account'), 'class' => 'fieldset-wide']
);
$fieldset->addType('filterselect', FilterSelect::class);
if ($model->getId()) {
$fieldset->addField('entity_id', 'hidden', ['name' => 'entity_id']);
}
$fieldset->addField(
'user_name',
'text',
[
'name' => 'user_name',
'label' => __('User Name'),
'title' => __('User Name'),
'required' => true,
'note' => __('Set the unique name for account.')
]
);
$fieldset->addField(
'access_data',
'filterselect', //custom type
[
'name' => 'access_data',
'label' => __('Access data'),
'options' => $this->getOptions(),
'multiple' => true,
'required' => true,
]
);
if (!empty($model->getData())) {
$data = $model->getData();
if (isset($data['access_data'])) {
$data['access_data'] = explode(',', $data['access_data'] ?? '');
}
$form->setValues($data);
}
$this->setForm($form);
return parent::_prepareForm();
}
/**
* Get options
*
* @return array
*/
public function getOptions()
{
return [
["value" => "1", "label" => "Customer"],
["value" => "2", "label" => "Admin"],
["value" => "3", "label" => "Seller"],
["value" => "4", "label" => "Guest"],
];
}
/**
* Prepare label for tab
*
* @return \Magento\Framework\Phrase
*/
public function getTabLabel()
{
return __('Blog Account');
}
/**
* Prepare title for tab
*
* @return \Magento\Framework\Phrase
*/
public function getTabTitle()
{
return __('Blog Account');
}
/**
* CanShowTab
*
* @return bool
*/
public function canShowTab()
{
return true;
}
/**
* IsHidden
*
* @param bool
*/
public function isHidden()
{
return false;
}
/**
* Check permission for passed action
*
* @param string $resourceId
* @return bool
*/
protected function _isAllowedAction($resourceId)
{
return $this->_authorization->isAllowed($resourceId);
}
}
Step-5: Add the custom type in block form using $fieldset->addType(‘filterselect’, FilterSelect::class);, This custom type’s “filterselect” field data handling and rendering by block file : Webkul\Custom\Block\Adminhtml\Widget\Form\Element\FilterSelect.php
<?php
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
namespace Webkul\Custom\Block\Adminhtml\Widget\Form\Element;
use Magento\Framework\Data\Form\Element\AbstractElement;
use Magento\Framework\Data\Form\Element\Factory as ElementFactory;
use Magento\Framework\Data\Form\Element\CollectionFactory;
use Magento\Framework\Escaper;
use Magento\Framework\Serialize\SerializerInterface;
/**
* Class FilterSelect.
*/
class FilterSelect extends AbstractElement
{
/**
* @var \Magento\Framework\View\LayoutInterface
*/
protected $layout;
/**
* @var SerializerInterface
*/
protected $serializer;
/**
* Constructor.
*
* @param ElementFactory $elementFactory
* @param CollectionFactory $collectionFactory
* @param Escaper $escaper
* @param \Magento\Framework\View\LayoutInterface $layout
* @param SerializerInterface $serializer
* @param array $data
*/
public function __construct(
ElementFactory $elementFactory,
CollectionFactory $collectionFactory,
Escaper $escaper,
\Magento\Framework\View\LayoutInterface $layout,
SerializerInterface $serializer,
array $data = []
) {
parent::__construct($elementFactory, $collectionFactory, $escaper, $data);
$this->layout = $layout;
$this->serializer = $serializer;
$this->setType('filterselect');
}
/**
* @inheritdoc
*/
public function getElementHtml()
{
$html = $this->layout->createBlock(\Magento\Framework\View\Element\Template::class)
->setTemplate('Webkul_Custom::business/filterselect.phtml')
->setTemplateConfiguration($this->getCustomConfiguration())
->toHtml();
$html .= $this->getAfterElementHtml();
return $html;
}
/**
* Get custom configuration
*
* @return string
*/
public function getCustomConfiguration()
{
$data = $this->getData();
$defultConfiguration = $this->getDefaultConfiguration();
foreach($defultConfiguration as $key => $configuration){
if(isset($data[$key])) {
$defultConfiguration[$key] = $data[$key];
}
}
return $this->serializer->serialize($defultConfiguration);
}
/**
* Get defaults configuration
*
* @return array
*/
public function getDefaultConfiguration()
{
$data = $this->getData();
$configurationData =[
"options" => [],
"listVisible" => false,
"value" => [],
'filterOptions' => true,
"chipsEnabled" => true,
"multiple" => true,
"showFilteredQuantity" => true,
"showCheckbox" => false,
"filterRateLimit" => 500,
"closeBtn" => true,
"closeBtnLabel" => __('Done'),
"quantityPlaceholder" => __('options'),
"hoverClass" => '_hover',
"selectedPlaceholders" => [
"defaultPlaceholder" => __('Select...'),
"lotPlaceholders" => __('Selected')
],
"component" => "Magento_Ui/js/form/element/ui-select",
"template" => "Webkul_Custom/filterselect", // custom template file
"elementData" => [
"name" => $this->getName(),
"id" => $this->getHtmlId(),
],
"required_entry" => isset($data['required']) ? $data['required'] : false
];
return $configurationData;
}
}
Step 6: Create a phtml template file which is mentioned in getElementHtml() method of Step 5, view/adminhtml/templates/business/filterselect.phtml
<?php
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
?>
<div data-bind="scope: 'customFilterSelect'">
<!-- ko template: getTemplate() --><!-- /ko -->
</div>
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/core/app": {
"components": {
"customFilterSelect": <?= /* @noEscape */ $block->getTemplateConfiguration() ?>
}
}
}
}
</script>
Step 7: Create a custom template file which is mentioned in getDefaultConfiguration() method of Step 5, view/adminhtml/web/template/filterselect.html
<div
class="admin__action-multiselect-wrap action-select-wrap"
tabindex="0"
data-bind="
attr: {
id: uid
},
css: {
_active: listVisible,
'admin__action-multiselect-tree': isTree()
},
event: {
focusin: onFocusIn,
focusout: onFocusOut,
keydown: keydownSwitcher
},
outerClick: outerClick.bind($data)
">
<!-- ko if: (!hasData() && multiple) -->
<input type="hidden"
data-bind="
attr: {
id: elementData.id,
name: elementData.name+'[]',
value: null
}
">
<!-- /ko -->
<!-- ko ifnot: chipsEnabled -->
<div
class="action-select admin__action-multiselect"
data-role="advanced-select"
data-bind="
css: {_active: multiselectFocus},
click: function(data, event) {
toggleListVisible(data, event)
}
">
<div class="admin__action-multiselect-text"
data-role="selected-option"
data-bind="text: setCaption()">
</div>
<!-- ko foreach: { data: getSelected(), as: 'option'} -->
<input type="hidden"
data-bind="
attr: {
id: $parent.elementData.id + value,
name: $parent.elementData.name +'[]',
value: value
}
">
<!-- /ko -->
</div>
<!-- /ko -->
<!-- ko if: chipsEnabled -->
<div
class="action-select admin__action-multiselect"
data-role="advanced-select"
data-bind="
css: {_active: multiselectFocus},
click: function(data, event) {
toggleListVisible(data, event)
}
">
<div class="admin__action-multiselect-text"
data-bind="
visible: !hasData(),
i18n: selectedPlaceholders.defaultPlaceholder
">
</div>
<!-- ko foreach: { data: getSelected(), as: 'option'} -->
<span class="admin__action-multiselect-crumb">
<span data-bind="text: label">
</span>
<button
class="action-close"
type="button"
data-action="remove-selected-item"
tabindex="-1"
data-bind="click: $parent.removeSelected.bind($parent, value)
">
<span class="action-close-text" translate="'Close'"></span>
</button>
</span>
<input type="hidden"
data-bind="
attr: {
id: $parent.elementData.id + value,
name: $parent.elementData.name +'[]',
value: value
}
">
<!-- /ko -->
</div>
<!-- /ko -->
<div class="action-menu"
data-bind="css: { _active: listVisible }
">
<!-- ko if: filterOptions -->
<div class="admin__action-multiselect-search-wrap">
<input
class="admin__control-text admin__action-multiselect-search"
data-role="advanced-select-text"
type="text"
data-bind="
event: {
keydown: filterOptionsKeydown
},
attr: {id: uid+2},
valueUpdate: 'afterkeydown',
value: filterInputValue,
hasFocus: filterOptionsFocus
">
<label
class="admin__action-multiselect-search-label"
data-action="advanced-select-search"
data-bind="attr: {for: uid+2}
">
</label>
<div if="itemsQuantity"
data-bind="text: itemsQuantity"
class="admin__action-multiselect-search-count">
</div>
</div>
<!-- /ko -->
<ul class="admin__action-multiselect-menu-inner _root"
data-bind="
event: {
scroll: function(data, event){onScrollDown($data, event)}
}
">
<!-- ko foreach: { data: options, as: 'option'} -->
<li class="admin__action-multiselect-menu-inner-item _root"
data-bind="css: { _parent: $data.optgroup }"
data-role="option-group">
<div class="action-menu-item"
data-bind="
css: {
_selected: $parent.isSelected(option.value),
_hover: $parent.isHovered(option, $element),
_expended: $parent.getLevelVisibility($data),
_unclickable: $parent.isLabelDecoration($data),
_last: $parent.addLastElement($data),
'_with-checkbox': $parent.showCheckbox
},
click: function(data, event){
$parent.toggleOptionSelected($data, event);
},
clickBubble: false
">
<!-- ko if: $data.optgroup && $parent.showOpenLevelsActionIcon-->
<div class="admin__action-multiselect-dropdown"
data-bind="
click: function(event){
$parent.openChildLevel($data, $element, event);
},
clickBubble: false
">
</div>
<!-- /ko-->
<!--ko if: $parent.showCheckbox-->
<input
class="admin__control-checkbox"
type="checkbox"
tabindex="-1"
data-bind="attr: { 'checked': $parent.isSelected(option.value) }">
<!-- /ko-->
<label class="admin__action-multiselect-label">
<span data-bind="text: option.label"></span>
<span
if="$parent.getPath(option)"
class="admin__action-multiselect-item-path"
data-bind="text: $parent.getPath(option)"></span>
</label>
</div>
<!-- ko if: $data.optgroup -->
<!-- ko template: {name: $parent.optgroupTmpl, data: {root: $parent, current: $data}} -->
<!-- /ko -->
<!-- /ko-->
</li>
<!-- /ko -->
</ul>
<!-- ko if: $data.closeBtn -->
<div class="admin__action-multiselect-actions-wrap">
<button class="action-default"
data-action="close-advanced-select"
type="button"
data-bind="click: outerClick">
<span translate="closeBtnLabel"></span>
</button>
</div>
<!-- /ko -->
</div>
</div>
<!-- ko if: ($data.getSelected().length == 0 && required_entry) -->
<input type="hidden"
data-bind="
attr: {
name: 'custom_required',
class: 'required-entry',
value: null
}
">
<!-- /ko -->
Step 8: Create a block file for form, Webkul\Custom\Block\Adminhtml\Account\Edit\Form.php
<?php
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
namespace Webkul\Custom\Block\Adminhtml\Account\Edit;
class Form extends \Magento\Backend\Block\Widget\Form\Generic
{
/**
* Init form
*
* @return void
*/
protected function _construct()
{
parent::_construct();
$this->setId('blog_account_form');
$this->setTitle(__('Blog Account Information'));
}
/**
* Prepare form
*
* @return $this
*/
protected function _prepareForm()
{
$model = $this->_coreRegistry->registry('business_list_model');
$form = $this->_formFactory->create(
[
'data' => [
'id' => 'edit_form',
'enctype' => 'multipart/form-data',
'action' => $this->getData('action'),
'method' => 'post'
]
]
);
if (!empty($model->getData())) {
$data = $model->getData();
if (isset($data['access_data'])) {
$data['access_data'] = explode(',', $data['access_data'] ?? '');
}
$form->setValues($data);
}
$form->setUseContainer(true);
$this->setForm($form);
return parent::_prepareForm();
}
}
Step 9: Create a controller file for layout webkulblog_account_edit.xml , Webkul\Custom\Controller\Adminhtml\Account\Edit.php
<?php
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
namespace Webkul\Custom\Controller\Adminhtml\Account;
use Magento\Framework\Controller\ResultFactory;
use Webkul\Custom\Block\Adminhtml\Account\Edit as AccountEdit;
use Webkul\Custom\Block\Adminhtml\Account\Edit\Tabs;
class Edit extends \Magento\Backend\App\Action
{
/**
* @var string
*/
public const ADMIN_RESOURCE = "Webkul_Custom::accountedit";
/**
* @var \Magento\Framework\Registry
*/
private $registry;
/**
* @var \Webkul\Custom\Model\BusinessListFactory
*/
protected $businessListFactory;
/**
* @param \Magento\Backend\App\Action\Context $context
* @param \Magento\Framework\Registry $registry
*/
public function __construct(
\Magento\Backend\App\Action\Context $context,
\Magento\Framework\Registry $registry,
\Webkul\Custom\Model\BusinessListFactory $businessListFactory
) {
$this->registry = $registry;
$this->businessListFactory = $businessListFactory;
parent::__construct($context);
}
/**
* Execute
*
* @return \Magento\Backend\Model\View\Result\Page
*/
public function execute()
{
try {
$params = $this->getRequest()->getParams();
$businessListModel = $this->businessListFactory->create();
if (isset($params['entity_id']) && $params['entity_id']) {
$businessListModel->load($params['entity_id']);
if (!$businessListModel->getId()) {
$this->messageManager->addError(__('Requested account currently not available.'));
$resultRedirect = $this->resultRedirectFactory->create();
return $resultRedirect->setPath('*/*/');
}
}
$this->registry->register('business_list_model', $businessListModel);
$resultPage = $this->resultFactory->create(ResultFactory::TYPE_PAGE);
$resultPage->setActiveMenu('Webkul_Custom::webkulblog');
$resultPage->getConfig()->getTitle()->prepend(__('Account'));
$resultPage->addContent($resultPage->getLayout()->createBlock(AccountEdit::class));
$resultPage->addLeft($resultPage->getLayout()->createBlock(Tabs::class));
return $resultPage;
} catch (\Exception $e) {
$this->messageManager->addError($e->getMessage());
$this->_redirect('*/*/');
}
}
/**
* Check for is allowed
*
* @return boolean
*/
protected function _isAllowed()
{
return $this->_authorization->isAllowed(self::ADMIN_RESOURCE);
}
}
Step 10: Create a controller file for the save selected option, Webkul\Custom\Controller\Adminhtml\Account\Save.php
<?php
/**
* Webkul Software.
*
* @category Webkul
* @package Webkul_Custom
* @author Webkul
* @copyright Copyright (c) Webkul Software Private Limited (https://webkul.com)
* @license https://store.webkul.com/license.html
*/
namespace Webkul\Custom\Controller\Adminhtml\Account;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\View\Result\PageFactory;
class Save extends Action
{
/**
* @var Magento\Framework\View\Result\PageFactory
*/
protected $resultPageFactory;
/**
* @var Webkul\Custom\Model\BusinessListFactory */
protected $businessListFactory;
/**
* @var \Magento\Framework\Registry
*/
protected $coreRegistry = null;
/**
* @param Context $context
* @param PageFactory $resultPageFactory
* @param \Webkul\Custom\Model\BusinessListFactory $businessListFactory
* @param \Magento\Framework\Registry $coreRegistry
*/
public function __construct(
Context $context,
PageFactory $resultPageFactory,
\Webkul\Custom\Model\BusinessListFactory $businessListFactory,
\Magento\Framework\Registry $coreRegistry
) {
parent::__construct($context);
$this->resultPageFactory = $resultPageFactory;
$this->businessListFactory = $businessListFactory;
$this->coreRegistry = $coreRegistry;
}
/**
* Save User Data
*
* @return \Magento\Framework\App\Response\Http
*/
public function execute()
{
$resultRedirect = $this->resultRedirectFactory->create();
$data = $this->getRequest()->getParams();
if (isset($data['user_name'])) {
$userAcccessIds = '';
if (isset($data['access_data'])) {
$userAcccessIds = implode(',', $data['access_data']);
}
$data['access_data'] = $userAcccessIds;
$businessList = $this->businessListFactory->create();
$businessList->setData($data)->save();
$id = $businessList->getId();
$this->coreRegistry->register("entity_id", $id);
$this->messageManager->addSuccess("User data has been saved.");
return $resultRedirect->setPath('*/*/edit', ['entity_id' => $id]);
} else {
$this->messageManager->addError(
__('Something went wrong while saving the user data.')
);
return $resultRedirect->setPath('*/*/edit');
}
}
}
After this, a ui-select with a search filter using the block method will be displayed on your form.

Change custom type UI select element configuration in Step 4:
Note: Custom field element configuration changed according to the mentioned configuration in getDefaultConfiguration() method of Step 5 file.
$fieldset->addField(
'access_data', //Element Id
'filterselect', //custom type
[
'name' => 'access_data',
'label' => __('Access data'),
'options' => $this->getOptions(),
'multiple' => true,
'required' => true,
] // In array mentioned configuration of element
);
Meanwhile Please try the above example and If you have any Queries then please ask in the comment section below.
Thank you!

I want to select single option at a time, and I have Access Data in bulk like 40k+ so search keyword and get data ajax based instead of loading all options on load