Magento 2 Extend jQuery UI Widget

In the previous article I showed you how to create a new jQuery UI widget from scratch. Today will be a bit different and I’ll demonstrate how you can extend existing jQuery UI widgets to add bespoke functionality – sometimes the original functionality isn’t enough.

In our examples we will be extending the DropdownDialog widget.

Extending jQuery UI widget

To extend an existing jQuery UI widget we need to use the mixins configuration within our requirejs-config.js file like so:

var config = {
config: {
mixins: {
'mage/dropdown': {
'Magento_Theme/js/dropdown-mixin': true
}
}
}
};

Here we are adding in a new mixin using the widget name we want to extend, in this case mage/dropdown. We are then pointing it to our mixin file which is found under our theme directory. Its good practice to use the widget name in the mixin file name like we have done here.

Next create the following file under your theme directory:

app/design/frontend/<VendorName>/<ThemeName>/Magento_Theme/web/js/dropdown-mixin.js

To start with we will scaffold our file in its simplest form, add the following contents:

define([
'jquery'
], function ($) {
'use strict';

return function(originalWidget) {
console.log('mixin loaded');
return originalWidget;
};
});

We can now check to see if our mixin is being loaded successfully. The default Magento 2 install uses the dropdown mixin for the minicart found in the header, by refreshing the homepage and opening the dev console up you should see the mixin has successfully loaded.

At the moment it doesn’t do a whole lot except return the original widget with no changes. Now we know its loading we can look at how we would extend the functionality.

Amend the mixin contents to the following:

define([
'jquery'
], function ($) {
'use strict';

return function (originalWidget) {
$.widget('mage.dropdownDialog', $.mage.dropdownDialog, {
open: function () {
// add our new code here
console.log('dropdown opened');

// call super for the original functionality (optional)
return this._super();
}
});

return $.mage.dropdownDialog;
}
});

Now if you refresh the homepage and click the minicart dropdown found in the header you should see the log in the dev console. Thats quite a bit of code so lets break it down a bit.

First we are using the jQuery widget factory syntax:

$.widget('mage.dropdownDialog', $.mage.dropdownDialog, {...

The first argument is the named widget we are redefining. The second argument is the parent widget definition – the widget we are extending.

Note: notice they have the same name, this is because we are extending the original widget, we don’t want to create a brand new widget under a new name, we just want to extend what is already there.

From here we then decide what part of the widget we want to extend, in this case we are extending the open method.

We add a very basic change by adding a simple console log and then call _super which calls the parent open method with its original functionality. Depending on your needs, if you didn’t want the original functionality of the parent open method you could leave this off.

You can also add new methods as needed based on your functionality.

Create a new widget by extending an existing widget

So far in the above example we haven’t created a new widget with a custom name, we have simply extended the existing widget with some functionality changes. But you can also create a new widget based off an existing widget.

define([
'jquery',
'jquery/ui',
'mage/dropdown'
], function ($) {
'use strict';

$.widget('jason.mywidget', $.mage.dropdownDialog, {
// add functionality
});

return $.jason.mywidget;
});

The code is very similar to what we’ve seen already. The only changes made are we’ve added a new dependency mage/dropdown, removed the return wrapper function and then returned our new widget name at the end of the file.

That’s all there is to it! Hopefully this helps for those times when you need to adjust the existing jQuery UI widgets.