in JavaScript

Guide: How to use Vue.js with jQuery Plugins


I’m not sure I can recommend that for vue2 anymore. I’m not sure what that solution would be but I would probably go for components now.

The original article is here:

Working with Vue can be awesome. But you might know that it can also give you headaches, when you try to combine it with jQuery plugins or other libraries.

The problem is that jQuery works fundamentally different than Vue. Vue renders everything based of the component’s core data. jQuery is mostly meant to do simple click handling and has powerful abilities manipulate the DOM.

When I looked for help myself I have found some unsatisfying solutions where components did do all the initialization work.
Let me show you how I would combine Vue.js and jQuery.

What’s the goal?

In most cases you can omit using jQuery and find a simple Vue based solution to your problem. Modals, sliders and so on are pretty simple with a Vue component and CSS.

So the goal is to use powerful jQuery plugins that cannot be written quickly in Vue.

We will …

  • … use Vue directives to build a bridge to jQuery.
  • … initialize the plugin when the element is attached.
  • … destroy it when the element is detached.
  • … send events to notify the component.
  • … receive events from the component and pass them to the plugin.

Tutorial Time

I’ve picked Fengyuan Chen’s cropper plugin because it’s a very well written jQuery plugin that you probably cannot rewrite in the next 60 min. using Vue.js alone.
It’s complex and demonstrates how Vue.js can interact with it.


I’m going to describe how to get that working from the very beginning. Skip the parts you have already done.

Create the project

Congratulations you have a Vue.js project.

Install jQuery and cropper.js

Configure Webpack for jQuery and Vue directives

Add the jQuery source and directives folder to the Webpack alias map.
Normally Webpack would have included the compiled version of jQuery. The recommendation is to have the source included instead.

You can see that the Vue webpack template has added the components folder already. I usually add a bunch of other folders like directives, mixins, etc. For this example we only need to add directives.

This will help us importing dependencies without having to know the exact path. This is also beneficial when you refactor your app along the way. You don’t need to manage relative paths.

Edit build/webpack.base.conf.js and add the highlighted lines.

Don’t forget to add a comma at the end of the components line.

Prepare the App Component

I’m going to start with the component because I believe it’s easier to understand the beauty and simplicity of the component. You can start writing directives later immediately because you then know how to use them in components.

Replace the template in src/App.vue

Replace the script in src/App.vue

A few important things to notice here.

  • We don’t import jQuery nor do we have to deal with its initialization in the component.
  • The Cropper’s options are available as raw data.
  • The Cropper will be initialized when this gets rendered and will be destroyed when the view isn’t visible anymore.
  • The directive’s name will be available in the template as a kebab cased version. MyCropper would become my-cropper.
    To initialize it, we have to add v-my-cropper to an element in the component’s template.

Create the Cropper directive

This is the heart of this tutorial. We’re going to create a Cropper directive that deals with the lower level code DOM manipulation. In this case we’re going to initialize the cropper.

Custom directives provide a mechanism for mapping data changes to arbitrary DOM behavior.

Create src/directives/Cropper.js

The very core of every Vue.js directive is a plain object with bind, update and unbind functions.

  • bind: Will be called once the element is attached to the document.
  • update: Called once after bind and every time when the wired data changes. In this case cropOptions is an object. The Vue.js directive needs to know if it is an object. This is why we need to add  deep: true in this case.
  • unbind: Called when the DOM element is about to be removed. We destroy everything here and remove all event listeners.

There will be a couple of changes in Vue 2.
The vm instance is going to be passed as a function argument and won’t be set to this.
The directive’s update function will only be called on update and not initially after bind.

First run

We just did the bare minimum. Let’s see if it works so far.

There is only one quick thing missing. We didn’t add the cropper’s stylesheet yet. Let’s do this and run the app.

Add the first, highlighted line to src/main.js

Start the server.

When everything went fine you should see a photo and a cropbox that you can move around.


Like it so far? Subscribe to my articles.

Toggle on/off

From here on everything will be pretty easy. We’ll go through it case by case. But each will be almost too simple.

Let’s enabled and disable the cropper with a button. Think of switching from page to page or opening the cropper after a user has selected a file. That proves that the cropper can be initialized at any time.

Edit the script in src/App.vue

  • add showCropper: false to data.
  • add a method to toggle showCropper .

Edit the template in src/App.vue

  • Add a button with a @click handler.
  • Add a v-if directive to the img  tag.

Every time the image shows up your custom cropper directive’s bind and update functions will be called.

When showCropper is set to false the cropper’s unbind function will be called.

There isn’t much we can mess up from here on.
The cropper will be loaded when it is needed and unloaded after the user is done.

Changing options

We already have everything it takes to update the cropper’s options. If we had a plugin that would accept new options on existing jQuery instances then we wouldn’t have to create destroy and recreate the plugin. Unfortunately the cropper doesn’t allow this.

Let’s add a switch that changes whether or not the image is zoomable.

Edit the template in src/App.vue

Easy, right?

Getting data out of the directive

The cropper has a crop callback function. We’re going to emit an event whenever that callback will be called.

Edit src/directives/Cropper.js

Edit the App component’s script to handle crop events.

Edit the App component’s template to show the crop data.

As you’ve seen I have chosen to emit events from the directive and listen to them in the app component. Ask yourself why I choose to do that. I also could have chosen to create a method in the app component and use that to bind it to the cropper’s crop listener.

Anti-pattern options.crop = this.vm.handleCrop

Evoking actions from outside

This final change shows how events can flow from a component to a directive. We’re going to use that to call cropper’s actions. Let me show you how I would add a rotate button.

Edit the App component’s template and add the rotate button.

Edit src/directives/Cropper.js to add and remove the event listener.


Et voilà you’re done!

The beauty of this setup is that the directive is decoupled from the components and can be used multiple times per component. It will be initialized automatically right after the element has been attached to the DOM and will be destroyed before it gets removed.

I hope you have enjoyed that article. Feel free to message me or post something to the comments section if you have questions for suggestions.



Stay up to date with JavaScript.

Subscribe to get my latest articles by email.

Powered by ConvertKit
  • MaxArt

    That’s odd. In my recent Angular project, I’ve actually written an image cropper from scratch.
    Because I really didn’t want to include jQuery just for that.
    It took me a day, I could afford it and it came out quite well, with touch support too.

    The problem with old-school jQuery plugins is that just a handful of them really stood the passing of time. If you’re still including jQuery in your project, well, you can still give it a shot.
    But if you haven’t yet, try to follow tha philosphy behind your framework of choice first. There might be a component already waiting for you. Or if there isn’t, it could be your chance to contribute to the community.

    • Hi Max,

      I’m glad you’ve said that. You’re actually right. You should try to do it in Vue instead of getting jQuery plugins for everything. And in most cases you’ll be surprised how easy it is.

      There is a vue-cropper out there already:

      I’ve written this because in reality there are many different people out there, some of them might not know how to do a cropper from scratch and it would take them way longer then 1 day. Or they need richer version of a cropper and want to use the one I’ve mentioned there. You cannot get this cropper done in 1 day I think. It’s just too much.

      This approach is also interesting if you’re trying to integrate Vue.js as a proof of concept. You can swap out those directives with your own directives / components if you decide to stick with Vue.

      So in a ideal Vue setup you wouldn’t want to use jQuery. But then there is the real world.

      I’m really glad that you’ve mentioned that though because I feel like I could have made this point more clear.

    • highpitch

      Why reinvent the wheel? Take datepicker for example, it’s not a trivial implementation. People have made datepicker for Vue, but why not re-use jQuery plugin? If components are what Vue evangelize, how about re-use and not re-make?

      • MaxArt

        I think I’ve been clear about that.

  • Juukie14

    Thanks for sharing!

  • Pingback: Дайджест свежих материалов из мира фронтенда за последнюю неделю №227 (4 — 11 сентября 2016) -

  • Pingback: Front-End Development ( 11 September ) – Skokov()

  • Pingback: Vue.js | Pearltrees()

  • Hi G

  • Pingback: New job, new challenges and new directives (in Vue.js) – Fjakkarin()

  • Salim Jordan


    I’m in a similar situation now where I want to use one of the most venerable and rather complicated and jquery plugins (formBuilder — alongside Vue.

    I’ve got it all working by essentially (following pseudo-code)…
    import jquery
    import jquery-ui
    require formBuilder

    Inside of Vue::mounted {
    // do normal jquery stuff

    But as you alluded to, something just feels wrong it. :-/

    Would be keen to explore how directives in Vuejs2 might make it feel better; unless of course there is a native vuejs port of the functionality (haven’t found it yet)

    • Hey I don’t think this applies to Vue2 anymore since directives are not supposed to hold state. I will update the article so that this is clear.

      • Salim Jordan

        Hey thanks for that follow-up. I have not even ventured into directives. What would be your current general advice on integrating quality and complex jquery plugins into vue?

        • I didn’t need to do that anymore but I would probably go for components now.

          • Salim Jordan

            Ok, so you would do what I have already done. Basically in the component import jquery and require/import the desired plugin. Then in the mounted property, you would just invoke $(‘#some-id”).examplePlugin() etc.

            So, essentially the component is really just a wrapper around the jquery plugin. Similarly to what @highpitch:disqus was advocating: “If components are what Vue evangelize, how about re-use and not re-make…”