Magento 2 comes equipped with a wide range of JS widgets, ranging from alerts, tabs to navigations. Widgets provide basic functionalities while keeping their design and usage consistent throughout a Magento site. While each widget has multiple variables for developers to use, often you will find their functionals limited and want to augment them.

In this article, we’ll discuss how to extend the Javascript widgets in Magento 2, along with their use cases.

Add custom JS component

Per Magento 2’s standard, your custom JS should be placed in:

  • <theme_dir>/web/js for a theme
  • <theme_dir>/<VendorName>_<ModuleName>/web/js if it belongs to a module in a theme
  • <module_dir>/view/<area>/web/js if it belongs to a module. (*)

Additionally, to use your custom JS, you might want to create a requirejs-config.js file in your theme or module. This file must be placed in <theme_dir>, <theme_dir>/<module_dir> or <module_dir>/view/<area>, corresponding with the 3 JS locations we’ve listed above.

(*): available areas include frontend, adminhtml and base.

Extend a Magento widget

Let's say we have a custom module called Magenest_WidgetMod, and our custom JS component is at app/code/Magenest/WidgetMod/view/frontend/web/js/extendedwidget.js, which corresponds to frontend area.

This component must define:

  • jquery
  • The Original widget
  • Any other dependencies required by the custom component.

This component then uses $.widget to define a custom widget extending a Magento one, and return this custom widget.

For example, to extend Magento’s modal widget:

define([
    'jquery',
    'jquery/ui',
    'Magento_Ui/js/modal/modal'
], function ($) {

    $.widget('magenest.modal', $.mage.modal, {
        //modify functions and variables here
    });

    return $.magenest.modal;
});

Here you can add/modify variables from the original widget, or override functions. To trigger the original widget’s function within your modification, uses this._super()method.

Using the extended widget

Extended widgets can be used directly, via mapping, or via JS mixin. In this section, we’ll explore all three ways to use them, with pros and cons.

Direct use

Simply add the custom JS as a dependency in your script, for example:

define([
    'jquery',
    'jquery/ui',
    'Magenest_WidgetMod/js/extendedwidget'
],

With this method, you can control when and where to use an extended widget. It’s recommended if the modification is only seldom used.

JS Mapping

JavaScript resource mappings can be defined in requirejs-config.js which we’ve created above. Mapping, similar to references in Magento 2 PHP classes, can redirect uses of the original widget to the extended widget. For example, here’s the mapping of an original modal widget to our extended widget:

var config = {
    map: {
        '*': {
         'Magento_Ui/js/modal/modal':'Magenest_WidgetMod/js/extendedwidget'
        }
    }
};

requirejs-config.js is area-dependent, and will redirect all uses of original widget in this area to the extended widget.

This method is ideal for extending all usages of the widget within specified area. However, if a widget is extended from multiple places, you may run into situations in which not all extended functionalities are loaded, depending on module sequences. The two ways to work around this issue would be:

  • Set appropriate module sequence and requirejs sequence
  • Use JS mixin instead of mapping

For module sequence workaround, in the most simple case (2 custom component extending the same widget), and you want one to load before another (i.e A then B ) you have to do the following:

  • Module B loads after module A (using <sequence> tab in module.xml )
  • Custom component A extends the original widget, then custom component B extends custom component A

This workaround is not recommended due to high complexity as the number of modules installed in Magento increases. Therefore JS mixin should be your choice.

JS Mixin

In Magento, a mixin is a class whose methods are added to, or mixed in, with another class.

A base class includes the methods from a mixin instead of inheriting from it. This allows adding to or modifying the behavior of the base class by adding different mixins to it.

To use JS Mixin, add the following to your requirejs-config.js

var config = {
    'config': {
        'mixins': {
            'Magento_Ui/js/modal/modal': {
                'Magenest_WidgetMod/js/extendedwidget: true
            }
        }
    }
};

And made some changes to the custom JS component:

  • The original widget can be dropped from the list of dependencies
  • Custom component returns function (widget)

Our custom component will look like the following:

define([
    'jquery',
    'jquery/ui',
], function ($) {
    return function (widget) {
    	$.widget('magenest.modal', widget, {
        	//modify functions and variables here
    	});
    	return $.magenest.modal;
	};
});

Mixin method allows for modifying the widget from multiple sources, and each modification can be enabled/disabled from requireJs easily. Similar to JS mapping, mixin is applied for the whole area.

READ MORE. How to write KnockoutJs in Magento 2 - Magenest blog

SUMMARY

Widgets are a very useful tool in Magento 2 and being able to leverage them to your use cases is a good skill to have for any Magento developer.

We hope you have learned something useful from this article, please let us know if you want to discuss anything on the topic of Javascript widgets in the comment section below.