How to add Tab in Form Ui Component
Unfortunately, I don't think any of the other answers will work. One (the link to a tutorial) isn't even a UI Component. It is possible to add tabs with a UI Component. My example is for Magento 2.2 +, but I suspect it will work in earlier versions if adjusted for the old UI Component syntax.
Step #1
The following are the necessary requirements for making a UI Component with tabs work (replace all references to "referral" with your UI Component name):
<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="label" xsi:type="string" translate="true">Referral</item>
<item name="js_config" xsi:type="array">
<item name="provider" xsi:type="string">referral_form.referral_form_data_source</item>
</item>
</argument>
<settings>
<layout>
<!-- I assume there are other options; set the layout handle accordingly -->
<navContainerName>left</navContainerName>
<type>tabs</type>
</layout>
<deps>
<dep>referral_form.referral_form_data_source</dep>
</deps>
</settings>
<dataSource name="referral_form_data_source">
<!-- ... -->
</dataSource>
<fieldset name="referral_fieldset">
<settings>
<label translate="true">General Info</label>
</settings>
<!-- Each fieldset is a new tab -->
</fieldset>
</form>
Note: most of your example UI Component code is correct, but you need to add the following to the <settings>
node:
<navContainerName>left</navContainerName>
<type>tabs</type>
Step #2
Set the layout on the page in the layout XML file: <page layout="admin-2columns-left"/>
Magento_Customer/view/base/ui_component/customer_form.xml
is a good example in the core.
Replace below code in your roaming_form.xml file.
<?xml version="1.0" encoding="UTF-8"?>
<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">roaming_form.roaming_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Roaming Details</item>
<item name="template" xsi:type="string">templates/form/collapsible</item>
</argument>
<settings>
<buttons>
<button name="delete" class="Vendor\Module\Block\Adminhtml\Roaming\Edit\Buttons\Delete"/>
<button name="save" class="Vendor\Module\Block\Adminhtml\Roaming\Edit\Buttons\Save"/>
<button name="back">
<url path="*/*/"/>
<class>back</class>
<label translate="true">Back</label>
</button>
</buttons>
<namespace>roaming_form</namespace>
<dataScope>data</dataScope>
<deps>
<dep>roaming_form.roaming_form_data_source</dep>
</deps>
</settings>
<dataSource name="roaming_form_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">Vendor\Module\Ui\DataProvider\Form\RoamingDataProvider</argument>
<argument name="name" xsi:type="string">roaming_form_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">entity_id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
</argument>
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
</item>
</argument>
<settings>
<submitUrl path="mobifone/roaming/save"/>
</settings>
</dataSource>
<fieldset name="roaming_details">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="collapsible" xsi:type="boolean">true</item>
<item name="label" xsi:type="string" translate="true">Roaming Details</item>
</item>
</argument>
<field name="entity_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="visible" xsi:type="boolean">false</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">current_roaming</item>
</item>
</argument>
</field>
<!--<field name="product_id">-->
<!--<argument name="data" xsi:type="array">-->
<!--<item name="config" xsi:type="array">-->
<!--<item name="label" xsi:type="string">Product ID</item>-->
<!--<item name="visible" xsi:type="boolean">true</item>-->
<!--<item name="dataType" xsi:type="string">text</item>-->
<!--<item name="formElement" xsi:type="string">input</item>-->
<!--<item name="source" xsi:type="string">current_roaming</item>-->
<!--</item>-->
<!--</argument>-->
<!--</field>-->
<field name="roaming_name">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string">Roaming Name</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">current_roaming</item>
</item>
</argument>
</field>
<field name="roaming_image">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">string</item>
<item name="source" xsi:type="string">current_roaming</item>
<item name="label" xsi:type="string" translate="true">Roaming Image</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="formElement" xsi:type="string">fileUploader</item>
<item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
<item name="previewTmpl" xsi:type="string">Magento_Catalog/image-preview</item>
<item name="dataScope" xsi:type="string">image</item>
<item name="required" xsi:type="boolean">false</item>
<item name="sortOrder" xsi:type="number">13</item>
<item name="uploaderConfig" xsi:type="array">
<item name="url" xsi:type="url" path="mobifone/roaming_image/upload"/>
</item>
</item>
</argument>
</field>
<field name="description">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
</item>
<item name="label" xsi:type="string">Description</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">wysiwyg</item>
<item name="template" xsi:type="string">ui/form/field</item>
<item name="wysiwyg" xsi:type="boolean">true</item>
<item name="source" xsi:type="string">current_roaming</item>
</item>
</argument>
</field>
</fieldset>
<fieldset name="list_product">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="collapsible" xsi:type="boolean">true</item>
<item name="label" xsi:type="string" translate="true">List Products</item>
</item>
</argument>
<insertListing name="products">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="source" xsi:type="string">products</item>
</item>
</argument>
<settings>
<externalData>id</externalData>
<externalProvider>${ $.ns }.product_listing_roaming</externalProvider>
<selectionsProvider>${ $.ns }.${ $.ns }.columns.ids</selectionsProvider>
<autoRender>true</autoRender>
<dataScope>product_listing_roaming</dataScope>
<ns>product_listing_roaming</ns>
</settings>
</insertListing>
</fieldset>
</form>
You have to just add below line to make any tab collapsible.
<item name="collapsible" xsi:type="boolean">true</item>
Replace below code in your roaming_form.xml file
<?xml version="1.0" encoding="UTF-8"?>
<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">roaming_form.roaming_form_data_source</item>
</item>
<item name="label" xsi:type="string" translate="true">Roaming Details</item>
<!--item name="template" xsi:type="string">templates/form/collapsible</item-->
</argument>
<settings>
<buttons>
<button name="delete" class="Vendor\Module\Block\Adminhtml\Roaming\Edit\Buttons\Delete"/>
<button name="save" class="Vendor\Module\Block\Adminhtml\Roaming\Edit\Buttons\Save"/>
<button name="back">
<url path="*/*/"/>
<class>back</class>
<label translate="true">Back</label>
</button>
</buttons>
<namespace>roaming_form</namespace>
<dataScope>data</dataScope>
<deps>
<dep>roaming_form.roaming_form_data_source</dep>
</deps>
<layout>
<navContainerName>left</navContainerName>
<type>tabs</type>
</layout>
</settings>
<dataSource name="roaming_form_data_source">
<argument name="dataProvider" xsi:type="configurableObject">
<argument name="class" xsi:type="string">Vendor\Module\Ui\DataProvider\Form\RoamingDataProvider</argument>
<argument name="name" xsi:type="string">roaming_form_data_source</argument>
<argument name="primaryFieldName" xsi:type="string">entity_id</argument>
<argument name="requestFieldName" xsi:type="string">id</argument>
</argument>
<argument name="data" xsi:type="array">
<item name="js_config" xsi:type="array">
<item name="component" xsi:type="string">Magento_Ui/js/form/provider</item>
</item>
</argument>
<settings>
<submitUrl path="mobifone/roaming/save"/>
</settings>
</dataSource>
<fieldset name="roaming_details">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">Roaming Details</item>
<item name="sortOrder" xsi:type="number">10</item>
</item>
</argument>
<field name="entity_id">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="visible" xsi:type="boolean">false</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">current_roaming</item>
</item>
</argument>
</field>
<field name="roaming_name">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string">Roaming Name</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">input</item>
<item name="source" xsi:type="string">current_roaming</item>
</item>
</argument>
</field>
<field name="roaming_image">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="dataType" xsi:type="string">string</item>
<item name="source" xsi:type="string">current_roaming</item>
<item name="label" xsi:type="string" translate="true">Roaming Image</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="formElement" xsi:type="string">fileUploader</item>
<item name="elementTmpl" xsi:type="string">ui/form/element/uploader/uploader</item>
<item name="previewTmpl" xsi:type="string">Magento_Catalog/image-preview</item>
<item name="dataScope" xsi:type="string">image</item>
<item name="required" xsi:type="boolean">false</item>
<item name="sortOrder" xsi:type="number">13</item>
<item name="uploaderConfig" xsi:type="array">
<item name="url" xsi:type="url" path="mobifone/roaming_image/upload"/>
</item>
</item>
</argument>
</field>
<field name="description">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="validation" xsi:type="array">
<item name="required-entry" xsi:type="boolean">true</item>
</item>
<item name="label" xsi:type="string">Description</item>
<item name="visible" xsi:type="boolean">true</item>
<item name="dataType" xsi:type="string">text</item>
<item name="formElement" xsi:type="string">wysiwyg</item>
<item name="template" xsi:type="string">ui/form/field</item>
<item name="wysiwyg" xsi:type="boolean">true</item>
<item name="source" xsi:type="string">current_roaming</item>
</item>
</argument>
</field>
</fieldset>
<fieldset name="list_product">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="label" xsi:type="string" translate="true">List Products</item>
<item name="sortOrder" xsi:type="number">10</item>
</item>
</argument>
<insertListing name="products">
<argument name="data" xsi:type="array">
<item name="config" xsi:type="array">
<item name="source" xsi:type="string">products</item>
</item>
</argument>
<settings>
<externalData>id</externalData>
<externalProvider>${ $.ns }.product_listing_roaming</externalProvider>
<selectionsProvider>${ $.ns }.${ $.ns }.columns.ids</selectionsProvider>
<autoRender>true</autoRender>
<dataScope>product_listing_roaming</dataScope>
<ns>product_listing_roaming</ns>
</settings>
</insertListing>
</fieldset>