Lightning Flow iFrame Plugin

Introduction

I was working with a client to develop a new job request process. We wanted to allow external users to directly input the details of their job request in an external flow. I created and tested the flow, exposed it using VisualForce on an externally available Salesforce site, and iFramed it on the client’s WordPress site. 

Then I ran into some issues. 

  • The multi-page flow changed height depending on the user input. Unfortunately, the iFrame had a static height.  
  • I needed to pass input variables from the parent page to the iFrame 

So I developed a plugin to solve for these problems

This plugin utilizes the great cross-domain iframe resizer from David J. Bradshaw.

Features

  • Dynamic iFrame height adjustment: responsive to Flow content and parent window responsive width
  • Pass all query strings parent page to the iFrame 
  • Set manual querystring values in shortcode 
  • Finish URL for redirect on flow complete

Implementation Options

For folks running WordPress, I have a plugin available in the directory.

Folks looking to implement on any other site can use the pure javascript implementation

Shortcode Format and Options

[Lightning-Flow-iFrame iframeurl="https://..." endurl="https://..." height="50px" extraqs="key=value" ease="true||false" easespeed=".2" lazy="true"]

AttributeDescriptionAllowed ValuesRequiredDefault
iframeurlurl of the public visualforce page rendering the flowfull urltrue“https://threelevers.secure.force.com/demo/iFrameDemo”
endurlurl to redirect folks to upon completing the flowfull urlfalsenone
heightinitial height of the iframe in pixels before fully loadednumber of pixels (i.e. “75px”)false“50px”
extraqsany querystring you want to pass to the iframe, in addition to the querystrings on the parent page. key/value pair separated by “=”. pairs separated “&” (example “foo=bar&this=that”)falsenone
easeset if the height adjustment of the iframe is eased“true” or “false”false“false”
easespeedspeed of the ease in secondsany number (example “.5” or “2”)false“.2”
lazydesignate ‘loading=”lazy”‘ to iframe“true” or “false”false“true”

Demo

The shortcode used to embed the demo flow:
[Lightning-Flow-iFrame iframeurl="https://threelevers.secure.force.com/demo/iFrameDemo" endurl="https://threelevers.com/plugins/iframe-embed/iframe-finish-demo/" height="60px" extraqs="count=11" ease="true"]

Test passing parameters via querystring by going to:
https://threelevers.com/plugins/iframe-embed/?count=7

				
					<apex:page id="iFrame-Demo" showHeader="false" docType="html-5.0" lightningStyleSheets="true" sidebar="false" standardStylesheets="false">
    <html>

    <head>
        <apex:includeLightning />
        <meta content="width=device-width, initial-scale=1.0" name="viewport" />
        <style>
            body {
                background: #efefef !important;
                color: #333;
            }
        </style>
        <script type='text/javascript' src='https://threelevers.com/wp-content/plugins/lightning-flow-iframe/js/iframeResizer.contentWindow.min.js' id='iframe-resizer'></script>
    </head>

    <body class="slds-scope">
            <div id="flowContainer" >
                <div id="Spinner" class="demo-only demo-only_viewport" style="height:6rem;position:relative">
                    <div role="status" class="slds-spinner slds-spinner_medium">
                        <span class="slds-assistive-text">Loading</span>
                        <div class="slds-spinner__dot-a"></div>
                        <div class="slds-spinner__dot-b"></div>
                    </div>
                </div>
            </div>
            <script>
                var statusChange = function(event) {
                    if (event.getParam("status") === "FINISHED") {
                        // Control what happens when the interview finishes
                        var url = "{!$CurrentPage.parameters.endUrl}"; //capture value entered in shortcode

                        //check if any value was given for endurl
                        if (url.length > 1) {
                            window.parent.location.href = url; //redirect to endUrl
                        }
                        var outputVariables = event.getParam("outputVariables");
                        var key;
                        for (key in outputVariables) {
                            if (outputVariables[key].name === "myOutput") {
                                // Do something with an output variable
                            }
                        }
                    }
                };
                $Lightning.use("c:FlowOutApp", function() {
                    // Create the flow component and set the onstatuschange attribute
                    $Lightning.createComponent("lightning:flow", {
                            "onstatuschange": statusChange
                        },
                        "flowContainer",
                        function(component) {
                            // Set the input variables
                            var inputVariables = [{
                                name: 'inputDivCount',
                                type: 'String',
                                value: '{!$CurrentPage.parameters.count}'
                            }];
                            ///////////
                            let height;
                            var checkExist = setInterval(function() {
                                height = document.body.scrollHeight;
                                window.parent.postMessage({
                                    frameHeight: height
                                }, '*');
                                console.log(height);
                            }, 500); // check every 500ms
                            ///////////
                            document.getElementById('Spinner').hidden = true;
                            // Start an interview in the flowContainer div, and 
                            // initializes the input variables.
                            component.startFlow("Expanding_Flow", inputVariables);

                        }
                    );
                });
            </script>

    </body>

    </html>
</apex:page>
				
			

Instructions

  1. Install the lightning-flow-iframe plugin (WordPress implementation only) 
  2. Prepare Lighting Flow on Visualforce page
  3. Make Visualforce Public
  4. Add shortcode (WordPress only) or code block (other sites) to your page

1. Install Plugin

2. Prepare Lightning Flow on Visualforce page

Follow the example from Salesforce to render the flow on a Visualforce page.

Next, you will need to add some lines of code to the Visualforce page to allow it it communicate with the parent page on which you will iframe it.

Add the javascript file right before the closing </head> tag. Be sure to update domain name to your domain. 

				
					 <script type='text/javascript' src='https://DOMAINNAME/wp-content/plugins/lightning-flow-iframe/js/iframeResizer.contentWindow.min.js' id='iframe-resizer'></script>

				
			

Modify FINISHED behavior to redirect to url set in the shortcode.

				
					if (event.getParam("status") === "FINISHED") {
    // Control what happens when the interview finishes
    var url = "{!$CurrentPage.parameters.endUrl}"; //capture value entered in shortcode

    //check if any value was given for endurl
    if (url.length > 1) {
        window.parent.location.href = url; //redirect to endUrl
    }
				
			

Optional
If you need to pass input variables to the flow, modify your inputVariables collection to reflect the variable names you will use. See the following example:

				
					// Set the input variables
var inputVariables = [{
    name: 'inputName1', //named Flow input variable
    type: 'String', //variable data type
    value: '{!$CurrentPage.parameters.qsname}' //name of the querystring you will use to popuate the variable 
}];
				
			

Just above component.startFlow("myFlowName", inputVariables); add line 1-9 of the following code.

				
					let height;
var checkExist = setInterval(function() {
    height = document.body.scrollHeight;
    window.parent.postMessage({
        frameHeight: height
    }, '*');
    console.log(height);
}, 500); // check every 500ms
///////////
// Start an interview in the flowContainer div, and 
// initializes the input variables.
component.startFlow("myFlowName", inputVariables);
				
			

3. Make Visualforce Page Public

Refer to the following documentation to create a Salesforce site with the proper configuration

4. Add shortcode to page

Add shortcode to your page. Follow the Shortcode Format and Options

Feedback and Support

Support for the WordPress plugin is available here.

 

If you need support for the javascript implementation, please complete the form below and I will get back to you when I am able.