How to add modal popup in Magento 2

Today, I would like to talk about modal popup. Magento 2 has a great built in possibility to easily add a popup to any place on your page. Let me quickly go through all the necessary files. I will provide you with two examples from my real tasks as it is really likely you will have similar tasks to implement.

First of all, I would like to encourage you to check out theΒ Modal Widgets Magento 2 DocumentationΒ first. Then I am happy to share with you all the necessary code that you will need to add to your project. I will provide you with two examples and I will focus on a case where we will add modal popup which opens after clicking a link in Magento 2 project.

How to add modal popup to standard Magento 2 parts?

Let’s start with a case where we will add a link into the footer in order to add modal popup in our Magento 2 project after clicking the link.

Template

First of all, let’s add the necessary templates to our module or theme. They will be located inΒ vendor/vendor-name/module-name/view/frontend/templates/Β orΒ vendor/vendor-name/theme-name/module-name/templates/Β where β€œvendor-nameβ€œ, β€œtheme-name” and β€œmodule-name” needs to be replaced with your name of vendor, theme and module name. If you are not creating a new module, you can useΒ Magento_ThemeΒ module for this case.

In our example, we will create two phtml files. One file will be to display a link, another file will be to hold a static block. The content of our popup will be added into the static block, but you can also add it directly to the template. Theoretically we could create just one phtml file with the link and popup content, however I look at the problem from a bigger perspective. Maybe at some point we will want to open the popup automatically without clicking the link, or open the popup by clicking another link on the page. In order to make it more general I will create two phtml files.

note.phtml

First of all we need to add a template with our link. Let’s createΒ note.phtml file in your theme or module as mentioned above.

Solution 1
<div class="note"> 
   <a class="action popup-open" href="#"> 
       <span><?php echo __('Please, click to open popup') ?></span> 
   </a> 
</div> 
<?php echo $this->getChildHtml('popup') ?> 
<script type="text/x-magento-init"> 
{ 
Β   ".popup-open": { 
Β       "Vendor_ModuleName/js/popup": {} 
Β   } 
} 
</script>

Let’s focus for a while on each part of this code.

<div class="note"> 
Β   <a class="action popup-open" href="#"> 
Β Β   <span><?php echo __('Please, click to open popup') ?></span> 
Β   </a> 
</div>
We create a link with the specific class β€œpopup-open” which we will use to execute our script.
<?php echo $this->getChildHtml('popup') ?>
This is where I add the content template of the popup, but you can easily add it to any other part of the page. In this case β€œpopup” is the block name which I will add to my xml file later on.
<script type="text/x-magento-init"> 
{ 
Β   ".popup-open": { 
Β Β   "VendorName_ModuleName/js/popup": {} 
Β   } 
} 
</script>

In this part we execute our script. Notice, we use the class of the link β€œpopup-open” and we point to the js file with the name of β€œpopup.js” in the pathΒ β€œVendorName_ModuleName/js”, of course, you need to replace β€œVendorName” and β€œModuleName” with your custom names.

Solution 2
<div class="note"> 
Β   <a class="action popup-open" data-mage-init='{"VendorName_ModuleName/js/popup":{}}' href="#"> 
Β Β Β   <span><?php echo __('Please, click to open popup') ?></span> 
Β   </a> 
</div> 
<?php echo $this->getChildHtml('popup') ?>

In theΒ Solution 2Β we use a different way of initialising the script.

<a class="action popup-open"Β data-mage-init='{"VendorName_ModuleName/js/popup":{}}' href="#"> 
Β   <span><?php echo __('Please, click to open popup') ?></span> 
</a>

As you can see we don’t have aΒ <script>Β tag anymore, instead we haveΒ data-mage-init='{"VendorName_ModuleName/js/popup":{}}'Β where you need to replace β€œVendorName” and β€œModuleName” with your custom names.

What is the different between these two solutions?

In Solution 1 the script will be initialised on all elements with class β€œpopup-open” where in the Solution 2 it will be initialised only on this element.

popup.phtml

At this point I am adding an additional template to point to the static block.Β Why have I added another template instead of executing the static block directly? I already explained at the beginning of this post.

<div id="popup" style="display: none;"> 
Β   <?php echo $this->getChildHtml('popup-content') ?> 
</div>

In this case, β€œpopup” is the id of the block that I will use later on and β€œpopup-content” is the static block name that I will set in my xml file later on.

Layout

Our xml files will be added toΒ vendor/vendor-name/module-name/view/frontend/layout/Β orΒ vendor/vendor-name/theme-name/module-name/layout/Β where β€œvendor-nameβ€œ, β€œtheme-name” and β€œmodule-name” needs to be replaced with your name of vendor, theme and module name. If you are not creating a new module, you can useΒ Magento_ThemeΒ module for this case.

default.xml

As we are adding the link to the footer, I will useΒ default.xmlΒ file to add my templates, however feel free to add it to any place on the page as I mentioned earlier.

<?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>
        <referenceContainer name="footer">
            <block class="Magento\Framework\View\Element\Template" name="note-popup" as="note-popup" template="VendorName_ModuleName::note.phtml" after="-">
                <block class="Magento\Framework\View\Element\Template" name="popup" as="popup" template="VendorName_ModuleName::popup.phtml" after="-">
                    <block class="Magento\Cms\Block\Block" name="popup-content">
                        <arguments>
                            <argument name="block_id" xsi:type="string">popup-content</argument>
                        </arguments>
                    </block>
                </block>
            </block>
        </referenceContainer>
    </body>
</page>
Let’s talk about each of the parts of this code. I am adding a link template to the footer and point to another template which executes the static block.Β  Notice, that I named static block β€œpopup-content” which I use to add this block inΒ popup.phtmlΒ file. Again, you need to replace β€œVendorName” and β€œModuleName” with your custom names.

Javascript

Our last step will be to add a javascript file to our script.Β Our js file will be added toΒ vendor/vendor-name/module-name/view/frontend/web/js/Β orΒ vendor/vendor-name/theme-name/module-name/web/js/Β where β€œvendor-nameβ€œ, β€œtheme-name” and β€œmodule-name” needs to be replaced with your name of vendor, theme and module name. If you are not creating a new module, you can useΒ Magento_ThemeΒ module for this case.

popup.js

Let’s create a popup.js file where we will write code with our popup script.

;define( 
Β   [ 
Β Β Β   'jquery', 
Β Β Β   'Magento_Ui/js/modal/modal' 
Β   ], 
Β   function($) { 
Β      "use strict"; 
Β      //creating jquery widget 
Β      $.widget('VendorName.Popup', { 
Β Β Β Β Β Β Β   options: { 
Β Β Β Β Β Β Β Β Β Β   modalForm: '#popup', 
Β Β Β Β Β Β Β Β Β Β   modalButton: '.popup-open' 
Β         }, 
Β         _create: function() { 
Β             this.options.modalOption = this.getModalOptions(); 
Β             this._bind(); 
Β         }, 
Β         getModalOptions: function() { 
Β             /** * Modal options */ 
Β             var options = { 
Β Β Β Β Β Β Β Β Β Β Β Β Β   type: 'popup', 
Β Β Β Β Β Β Β Β Β Β Β Β Β   responsive: true, 
Β Β Β Β Β Β Β Β Β Β Β Β Β   clickableOverlay: false, 
Β Β Β Β Β Β Β Β Β Β Β Β Β   title: $.mage.__('PopUp'), 
Β Β Β Β Β Β Β Β Β Β Β Β Β   modalClass: 'popup', 
Β Β Β Β Β Β Β Β Β Β Β Β Β   buttons: [{ 
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β   text: $.mage.__('Yes, I got you!'), 
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β   class: '', 
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β   click: function () { 
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β   this.closeModal(); 
Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β Β   } 
Β Β Β Β Β Β Β Β Β Β Β Β Β   }] 
Β             };  
Β             return options; 
Β         }, 
Β          _bind: function(){ 
Β Β Β Β Β Β Β Β Β Β Β   var modalOption = this.options.modalOption; 
Β Β Β Β Β Β Β Β Β Β Β   var modalForm = this.options.modalForm; 
Β Β Β Β Β Β Β Β Β Β Β   $(document).on('click', this.options.modalButton, function(){ 
Β Β Β Β Β Β Β Β Β Β Β Β Β Β   $(modalForm).modal(modalOption); 
Β Β Β Β Β Β Β Β Β Β Β Β Β Β   $(modalForm).trigger('openModal'); 
Β Β Β Β Β Β Β Β Β Β Β   }); 
Β          } 
Β      }); 

Β Β     return $.VendorName.Popup; 
Β   } 
);

Notice that in the script I use β€œpopup” id of the popup content which is added toΒ popup.phtmlΒ file and I use β€œpopup-open” which is the class of the link inΒ link.phtmlΒ file. Moreover, remember to replace β€œVendorName” with your own custom name.

you will see the link in the footer as shown below. On click on that link, poup will open.

Popup As below:

How to add modal popup to knockout.js part in Magento 2?

Let’s focus on the example where you need to add a link just before theΒ Place OrderΒ button and add modal popup to the checkout in Magento 2. As you should know, checkout usesΒ knockout.jsΒ and the implementation is slightly different here.

Template

In this case weΒ will keep ourΒ popup.phtmlΒ file from the previous example, we will just add it in in a slightly different way into the xml file. However, before you continue, make sure you have addedΒ popup.phtmlΒ as mentioned above.

Our second file will be located in a different place, which isΒ vendor/vendor-name/module-name/view/frontend/web/template/Β orΒ vendor/vendor-name/theme-name/module-name/web/template/Β where β€œvendor-nameβ€œ, β€œtheme-name” and β€œmodule-name” needs to be replaced with your name of vendor, theme and module name. If you are not creating a new module, you can useΒ Magento_CheckoutΒ module for this case as we make the implementation into the checkout part.

note.html

Another file mentioned above will beΒ note.htmlΒ which has a similar structure toΒ note.phtml.

<div class="note"> 
Β Β Β Β <a class="action popup-open"data-bind="mageInit: {'VendorName_ModuleName/js/popup':{}}"Β href="#"> 
Β Β Β Β Β Β Β Β <span><!-- ko i18n: 'Please, click to open popup.'--><!-- /ko --></span> Β Β Β Β 
Β Β Β Β </a> 
</div>

Again,Β we use the class of the link β€œpopup-openβ€œ. I also initialised our script byΒ data-bindΒ calling our scriptΒ popup.js,Β really similar to Solution 2 in the previous example.

Layout

Our xml file, as in the previous example, will be added toΒ vendor/vendor-name/module-name/view/frontend/layout/Β orΒ vendor/vendor-name/theme-name/module-name/layout/Β where β€œvendor-nameβ€œ, β€œtheme-name” and β€œmodule-name” needs to be replaced with your name of vendor, theme and module name. If you are not creating a new module, you can useΒ Magento_CheckoutΒ module for this case as we make the implementation into the checkout part.

checkout_index_index.xml

In this case, we will use checkout_index_index.xml as we will focus on adding a popup to the checkout. If you are familiar with this file, you know that it is slightly different than the rest of the xml files.

<?xml version="1.0"?> 
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" layout="1column" 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="billing-step" xsi:type="array"> 
                                            <item name="children" xsi:type="array"> 
                                                <item name="payment" xsi:type="array"> 
                                                    <item name="children" xsi:type="array"> 
                                                        <item name="payments-list" xsi:type="array"> 
                                                            <item name="children" xsi:type="array"> 
                                                                <item name="order-comment" xsi:type="array"> 
                                                                    <item name="component" xsi:type="string">VendorName_ModuleName/js/checkout-popup-note</item> 
                                                                    <item name="displayArea" xsi:type="string">before-place-order</item> 
                                                                    <item name="dataScope" xsi:type="string">checkoutpopup</item> 
                                                                    <item name="provider" xsi:type="string">checkoutProvider</item> 
                                                                </item> 
                                                            </item> 
                                                        </item> 
                                                    </item> 
                                                </item> 
                                            </item> 
                                        </item> 
                                    </item> 
                                </item> 
                            </item> 
                        </item> 
                    </item> 
                </argument> 
            </arguments> 
        </referenceBlock>
         <referenceContainer name="footer"> 
            <block class="Magento\Framework\View\Element\Template" name="popup" as="popup" template="VendorName_ModuleName::popup.phtml" after="-"> 
                <block class="Magento\Cms\Block\Block" name="popup-content"> 
                    <arguments> 
                        <argument name="block_id" xsi:type="string">popup-content</argument> 
                    </arguments> 
                </block> 
            </block> 
        </referenceContainer> 
    </body> 
</page>
Let’s talk about each of the parts of this code. I am addingΒ checkout-popup.jsΒ which is the script to add myΒ note.htmlΒ file to the place just before theΒ Place OrderΒ button. I will talk about it later. I am also adding another template to the footer, with the content of the popup as in the previous example.Β  Notice, that I named the static block β€œpopup-content” which I use to run this block inΒ popup.phtmlΒ file. Again, you need to replace β€œVendorName” and β€œModuleName” with your custom names.

Javascript

In this case, we will keepΒ popup.jsΒ from the previous example. Before continuing, make sure you have this file as described in the first example.

Our second js file that is needed to addΒ the note.htmlΒ file to the checkout will be added toΒ vendor/vendor-name/module-name/view/frontend/web/js/Β orΒ vendor/vendor-name/theme-name/module-name/web/js/Β where β€œvendor-nameβ€œ, β€œtheme-name” and β€œmodule-name” needs to be replaced with your name of vendor, theme and module name. If you are not creating a new module, you can use Magento_Checkout module for this case as we make the implementation into the checkout part.

checkout-popup-note.js

;define( 
    [ 
        'ko', 
        'jquery', 
        'uiComponent' 
    ], 
    function (ko, $, Component) { 
        'use strict'; 
        return Component.extend({ 
            defaults: { 
                template: 'VendorName_ModuleName/note' 
            } 
        }); 
    } 
);

In this case, we just add theΒ note.htmlΒ file.