Migration to Lightning: What About My JavaScript Buttons?

Migrating to Salesforce Lightning Experience can be a daunting task.

Ultimately a migration does not make sense unless feature parity can be ensured for the features your users care about. When considering a LEX migration, talking about custom JavaScript buttons can be one of the more painful conversations you will have. Because you will lose them – Classic JavaScript buttons will not work in Lightning Experience. They will all have to be reworked. And because they are widely deployed, powerful, and quick to design and deploy, this can be a painful reality to face.

JavaScript buttons in Classic are everywhere. Most of our clients running Classic employ some flavor of custom JavaScript button. Before Process Builder, this was a great way to perform many non-trivial “if/then” tasks without requiring Apex. Create a related record? Update other related records? Navigate to other places on-click? Custom JavaScript buttons were a good answer. Not THE answer, not necessarily the RIGHT answer, but a viable answer. What made this approach especially popular amongst non-developer Consultants, Power Users and Administrators was the speed and relative ease with which these solutions could be put together and deployed without requiring knowledge of Apex. One simply had to 1) search the web to find an existing button example out there that was close to what one wanted, 2) modify as needed, and 3) deploy. These buttons could be put in place very quickly without requiring any code coverage or unit tests.

Fast forward to today. For better or worse this design pattern (AJAX Toolkit behind JavaScript button) is not supported in Lightning Experience and may never be supported in Lightning Experience. I choose to say this is “for better” because from an enterprise software perspective this move is for the better. LEX JavaScript security is greatly improved over Classic, and for enterprise software this is a big deal. To operate in this new reality, we will have to learn a different way. A better way. The LEX way.

Simple JavaScript Button Conversion… doing it the “LEX Way”

Simple Classic JavaScript buttons can be directly replaced (with no loss of functionality) with Quick Actions and/or Process Builder. As a starting point, always check to see if you can replace your Classic JavaScript button functionality with these solutions. As these solutions are already well-documented by Trailhead and other great resources, I will not demonstrate these simple examples. Let’s focus on a more complicated example.

Advanced JavaScript Button Conversion… doing it the “LEX Way”

Let’s focus on a more complicated example: a JavaScript button that – onclick – initiates a callout to an external ticketing system. By way of an Apex webservice method and a JavaScript button, a callout is performed from the standard Case page layout to an external ticketing system. A Case Number is passed to the external system, and that system responds with an external ID. This ID is received by SF and written back to the Case record, to a custom field named “External_Case_ID__c”.

Let’s look at how we would port this functionality over into Lightning. The way to do this is via a new Lightning Component that will be added to the Case Page Layout.


  1. You have an existing (functional) Classic JavaScript button that, on-click, invokes a callout to an external system via Apex.
  2. The callout (Apex) method is functional and uses the “webservice” keyword, allowing simple execution from the JavaScript button.

This is a common design pattern when using the AJAX Toolkit and JavaScript buttons to perform a callout. Let us start by examining your likely starting point. You will already have these pieces.

First Piece: JavaScript Button

Simple enough. This is a Detail Button on Case that, on-click, performs the following:

  1. Calls out to external web service, passes SF CaseNumber from Case being viewed.
  2. Receives back external ID for the Case, writes that value to field on Case, allowing us to track this Case in two systems (SF and External System).

Your Classic JavaScript button might look something like this:

Second Piece: Apex “webservice” method. Your Apex callout method (invoked via JavaScript button above) might look something like:

You don’t need to understand it, you just need to know “it works”. Having reviewed your current solution in Classic, let’s look at how we would replicate this functionality in Lightning Experience via a Lightning Component.

The LEX Way: Step 1) Create a Lightning Component (“Build the Button”)

This Lightning Component will be, for all practical purposes, the equivalent replacement for your JavaScript button. For this step, let’s use the standard Developer Console. From the Developer Console, click File > New > Lightning Component and give your component a Name. I will keep it simple and use “calloutExample”: 

Adjust your <aura stub as follows and save your component.

Lightning JavaScript Button

There is a lot of power in those simple lines. I will highlight some of the critical parts:

  • The keywords in <aura:component interface are important… flexipage:availableForRecordHome allows this component to be displayed on record page layouts in lightning, which is what we want. force:hasRecordId gives us access to the record id of the record being viewed in Lightning.
  • The controller keyword in the <aura:component tag allows this component to access the Apex resource named “calloutClass.cls”.
  • The <aura:attribute tags are attributes that are critical to this callout process: the Case sObject (name=”case”) and it’s ID (name=”recordId”).
  • The <aura:handler tag is a method that runs on load, automatically. We flesh out the doInit method to query the Case being viewed. Remember, this component is intended to be used on a record detail page, just like the Classic JavaScript button we are replacing.
  • The <lightning:button tag is the “button” equivalent that takes advantage of platform styling, specifically a nice green variant of button called “success”. This tag also specifies what happens onclick… the javascript method “makeCallout” is called.

The LEX Way: Step 2) Revise your webservice class

For a method to be visible and usable from a Lightning Component, the @AuraEnabled annotation must be used for that method. And while we are making minor changes to this class, let’s also add two simple methods to support a query and an update. All methods must be @AuraEnabled. We will use all three methods in our final solution.

Your revised calloutClass.cls should look like:

The LEX Way: Step 3) Create Component Controller (Javascript)

Create a Component Controller via the Developer Console. You can simply click on the “Controller” row in the console as shown, and a new controller stub will be created for you:

Next, modify your controller stub. Your final controller should look like:

This is a fairly simple controller, and much of this should be viewed as “boilerplate” as you will use this type of pattern for many of your controller or helper methods. Ultimately, there is no substitute for reviewing and understanding the official Lightning Component Documentation. Note the following:

  • The doInit function is run on component load (as it renders on the page layout) and calls the serverGetCase method from your calloutExampleController. This simply loads the Case into memory, so we can work with it and set its fields later.
  • The makeCallout function is invoked on button click (recall that your button references this method) and calls your original “makeCallout” webservice Apex method. If the callout is successful, the resulting string is written to the External_Case_ID__c field.
  • The call to helper.saveCase will be defined in our helper, defined below.

The LEX Way: Step 4) Create Component Helper (Javascript)

Create a Component Helper via the Developer Console, this is where we will write our updated Case to the SF database. You can simply click on the “Helper” row in the console as shown, and a new helper stub will be created for you:

Next, modify your helper stub. Your final helper should look like:

This is a fairly simple helper. Like our controller, much of this should be viewed as “boilerplate” as you will use this type of pattern for many of your controller or helper methods. Note the following:

  • The var action calls the serverSaveCase method from your “calloutClass.cls” Apex resource.
  • If successful, the page is refreshed via $A.get(“e.force:refreshView”).fire();

Step 5) Finished! Add the Component to the appropriate Page Layout.


We have provided the reader with a fully functional example of “porting” a Classic JavaScript button into the Lightning Framework, by way of a Lightning Component. This is one way to do it, but there are other ways. There are worse ways, and there are better ways. Optimization, simplification, testing, and refactoring are left as exercises for the reader.

Disclaimer: the intent of this post was NOT to teach Lightning Components or the Lightning Framework. It is assumed that the reader will engage with the official Documentation, including Trailheads. Stay engaged, keep learning, and have fun!

And finally, to confirm what you are thinking… YES, the “LEX Way” is definitely more involved than the Classic JavaScript button approach. But it can be learned in no time. And if you get stuck… Ask us how we can help with your lightning migration!


EightCloud has not disappointed. Right away, they stepped up to meet our aggressive timeline and dove right in. They are flexible with our changing needs and have remained incredibly responsive. I appreciate the proactive communication. I would highly recommend partnering with EightCloud!"

- Christie Madsen, Dreambox Learning

Let us craft a custom solution that will meet your current and future Salesforce needs and make your life easier.


Rotate Your Device

Partners and friends, we are proud to share the new EightCloud brand and website with you. Our transformation reflects our commitment to helping you achieve Salesforce excellence through a focus on efficiency, expertise and genuine partnership.

We wish you the best and look forward to connecting with you soon!

Show me the new site!