Before doing customizations, do the following. - Set Magento to developer mode - Do not edit default Magento code, instead add customizations in a separate module - Do not use Ui for your custom module name **Step 1: Create the JS implementation of the form UI component** In your `<your_module_dir>/view/frontend/web/js/view/` directory, create a .js file implementing the form. /*global define*/ define([ 'Magento_Ui/js/form/form' ], function(Component) { 'use strict'; return Component.extend({ initialize: function () { this._super(); // component initialization logic return this; }, /** * Form submit handler * * This method can have any name. */ onSubmit: function() { // trigger form validation this.source.set('params.invalid', false); this.source.trigger('customCheckoutForm.data.validate'); // verify that form data is valid if (!this.source.get('params.invalid')) { // data is retrieved from data provider by value of the customScope property var formData = this.source.get('customCheckoutForm'); // do something with form data console.dir(formData); } } }); }); **Step 2: Create the HTML template** Add the `knockout.js` HTML template for the form component under the `<your_module_dir>/view/frontend/web/`template directory. **Example:** <div> <form id="custom-checkout-form" class="form" data-bind="attr: {'data-hasrequired': $t('* Required Fields')}"> <fieldset class="fieldset"> <legend data-bind="i18n: 'Custom Checkout Form'"></legend> <!-- ko foreach: getRegion('custom-checkout-form-fields') --> <!-- ko template: getTemplate() --><!-- /ko --> <!--/ko--> </fieldset> <button type="reset"> <span data-bind="i18n: 'Reset'"></span> </button> <button type="button" data-bind="click: onSubmit" class="action"> <span data-bind="i18n: 'Submit'"></span> </button> </form> </div> **Clear files after modification** If you modify your custom .html template after it was applied on the store pages, the changes will not apply until you do the following: Delete all files in the `pub/static/frontend` and `var/view_preprocessed` directories. Reload the pages. **Step 3: Declare the form in the checkout page layout** To add content to the Shipping Information step, create a `checkout_index_index.xml` layout update in the `<your_module_dir>/view/frontend/layout/`. It should be similar to the following. <?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"> <body> <referenceBlock name="checkout.root"> <arguments> <argument name="jsLayout" xsi:type="array"> <item name="components" xsi:type="array"> <item name="checkout" xsi:type="array"> <item name="children" xsi:type="array"> <item name="steps" xsi:type="array"> <item name="children" xsi:type="array"> <item name="shipping-step" xsi:type="array"> <item name="children" xsi:type="array"> <item name="shippingAddress" xsi:type="array"> <item name="children" xsi:type="array"> <item name="before-form" xsi:type="array"> <item name="children" xsi:type="array"> <!-- Your form declaration here --> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </item> </argument> </arguments> </referenceBlock> </body> </page> **Static forms:** The following code sample shows configuration of the form that contains four fields: text input, select, checkbox, and date. This form uses checkout data provider (checkoutProvider) that is introduced in the Magento_Checkout module: <item name="custom-checkout-form-container" xsi:type="array"> <item name="component" xsi:type="string">%your_module_dir%/js/view/custom-checkout-form</item> <item name="provider" xsi:type="string">checkoutProvider</item> <item name="config" xsi:type="array"> <item name="template" xsi:type="string">%your_module_dir%/custom-checkout-form</item> </item> <item name="children" xsi:type="array"> <item name="custom-checkout-form-fieldset" xsi:type="array"> <!-- uiComponent is used as a wrapper for form fields (its template will render all children as a list) --> <item name="component" xsi:type="string">uiComponent</item> <!-- the following display area is used in template (see below) --> <item name="displayArea" xsi:type="string">custom-checkout-form-fields</item> <item name="children" xsi:type="array"> <item name="text_field" xsi:type="array"> <item name="component" xsi:type="string">Magento_Ui/js/form/element/abstract</item> <item name="config" xsi:type="array"> <!-- customScope is used to group elements within a single form (e.g. they can be validated separately) --> <item name="customScope" xsi:type="string">customCheckoutForm</item> <item name="template" xsi:type="string">ui/form/field</item> <item name="elementTmpl" xsi:type="string">ui/form/element/input</item> </item> <item name="provider" xsi:type="string">checkoutProvider</item> <item name="dataScope" xsi:type="string">customCheckoutForm.text_field</item> <item name="label" xsi:type="string">Text Field</item> <item name="sortOrder" xsi:type="string">1</item> <item name="validation" xsi:type="array"> <item name="required-entry" xsi:type="string">true</item> </item> </item> <item name="checkbox_field" xsi:type="array"> <item name="component" xsi:type="string">Magento_Ui/js/form/element/boolean</item> <item name="config" xsi:type="array"> <!--customScope is used to group elements within a single form (e.g. they can be validated separately)--> <item name="customScope" xsi:type="string">customCheckoutForm</item> <item name="template" xsi:type="string">ui/form/field</item> <item name="elementTmpl" xsi:type="string">ui/form/element/checkbox</item> </item> <item name="provider" xsi:type="string">checkoutProvider</item> <item name="dataScope" xsi:type="string">customCheckoutForm.checkbox_field</item> <item name="label" xsi:type="string">Checkbox Field</item> <item name="sortOrder" xsi:type="string">3</item> </item> <item name="select_field" xsi:type="array"> <item name="component" xsi:type="string">Magento_Ui/js/form/element/select</item> <item name="config" xsi:type="array"> <!--customScope is used to group elements within a single form (e.g. they can be validated separately)--> <item name="customScope" xsi:type="string">customCheckoutForm</item> <item name="template" xsi:type="string">ui/form/field</item> <item name="elementTmpl" xsi:type="string">ui/form/element/select</item> </item> <item name="options" xsi:type="array"> <item name="0" xsi:type="array"> <item name="label" xsi:type="string">Please select value</item> <item name="value" xsi:type="string"></item> </item> <item name="1" xsi:type="array"> <item name="label" xsi:type="string">Value 1</item> <item name="value" xsi:type="string">value_1</item> </item> <item name="2" xsi:type="array"> <item name="label" xsi:type="string">Value 2</item> <item name="value" xsi:type="string">value_2</item> </item> </item> <!-- value element allows to specify default value of the form field --> <item name="value" xsi:type="string">value_2</item> <item name="provider" xsi:type="string">checkoutProvider</item> <item name="dataScope" xsi:type="string">customCheckoutForm.select_field</item> <item name="label" xsi:type="string">Select Field</item> <item name="sortOrder" xsi:type="string">2</item> </item> <item name="date_field" xsi:type="array"> <item name="component" xsi:type="string">Magento_Ui/js/form/element/date</item> <item name="config" xsi:type="array"> <!--customScope is used to group elements within a single form (e.g. they can be validated separately)--> <item name="customScope" xsi:type="string">customCheckoutForm</item> <item name="template" xsi:type="string">ui/form/field</item> <item name="elementTmpl" xsi:type="string">ui/form/element/date</item> </item> <item name="provider" xsi:type="string">checkoutProvider</item> <item name="dataScope" xsi:type="string">customCheckoutForm.date_field</item> <item name="label" xsi:type="string">Date Field</item> <item name="validation" xsi:type="array"> <item name="required-entry" xsi:type="string">true</item> </item> </item> </item> </item> </item> </item> Hope this helps. **Note:** Use the extension https://www.fmeextensions.com/custom-checkout-fields-order-attributes-extension-magento-2.html to get it done effortlessly.