Responsive iframes for Shiny Apps

By Paul Campbell | March 15, 2018

Getting Shiny out into the wild

Shiny has really changed game in terms of analytical web-application development. Anyone with a solid grasp of R programming and some basic HTML + CSS knowledge can get production quality apps and dashboards up and running in days rather than months, and be in complete control of the process yourself. Furthermore, because it’s all open-source software, you have total ownership of the product you build - unlike many expensive off-the-shelf GUI solutions.

Problem

Although you have full ownership of your shiny app, one drawback is that you may run into trouble when it comes to deployment. Shiny apps don’t just work in the browser. R code can’t be run client-side like javascript can. And they can’t be deployed on a standard webserver. Shiny apps need to be hosted on a server with R and shiny installed and connected to a running R process. Whilst R is a fast growing language, support for it in the IT world remains relatively small, so this means you will generally be tasked with setting up your own hosting environment, outwith your standard web architecture. shinyapps.io from Rstudio is a very user-friendly service that will take care of hosting for you, or if you want more control, setting up your own shiny cloud server is an option. But this isolation can lead to a breakdown in integration between shiny content and regular web content.

Solution

One way around this is to embed shiny apps into standard webpages in an iframe. This is easily done with a standard iframe, however, shiny apps have a responsive design which means the height of the app is determined by the end users window size. This makes it difficult to seamlessly integrate dynamic content into the iframe which most commonly have a hard coded height attribute. This tends to result in either scroll bars appearing around the app or a big gaping void of existential abyss between the bottom of your app and the next piece of content on your webpage.

Luckily, David J. Bradshaw has built a javascript iframe-resizer library to help us fill this shiny void. Here is a shiny example of it in action on this very webpage.

The buttons below are part of a running shiny app hosted on shinyapps.io. Press some of them and see what happens…

How to do it

To acheive this behaviour we need:

  • one js script sourced in the shiny app
  • a tagged placeholder div at the point in the app you want to be ‘end’ (after all the charts ‘n tables)
  • another js script sourced in the parent HTML page
  • some iframe styling
  • the iframe itself
  • a final script telling iframeResizer to go to work on our iframe and look for the tagged <div>

I’m using cdn versions of the scripts but you can download them here and use local versions if you’d prefer.

So firstly, add this to your shiny app UI:

tags$head(
      tags$script(src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.contentWindow.min.js",
                  type="text/javascript")
      ),

Then find the spot in the UI you want to be endpoint and add this placeholder <div> 1:

HTML('<div data-iframe-height></div>')

Finally, add this code to the parent HTML page you are embedding the shiny app in, in the position you want the app to render (change the source url in the iframe to your shiny app url). For the blogdowners amongst us, you can paste this HTML code straight into any Rmarkdown or regular markdown document:

<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/iframe-resizer/3.5.16/iframeResizer.min.js"></script>
<style>
  iframe {
    min-width: 100%;
  }
</style>
<iframe id="myIframe" src="https://YOUR_SHINYAPP_URL.com" scrolling="no" frameborder="no"></iframe>
<script>
  iFrameResize({
    heightCalculationMethod: 'taggedElement'
  });
</script>

And that should be that!

Going forward

There’s real potential for shiny to find it’s way onto more webpages in the public domain. With the ability to match the parent webpage’s CSS styling combined with responsive iframe integration, shiny app development and design can be tailored for webpages they are destined for. Here’s a great example of a shiny app built into a full website. h/t Joshua Kunst.

If you’re interested in bespoke web-applications for your website, get in touch with us here.

Thanks for reading.


  1. You can skip this step and use heightCalculationMethod: 'lowestElement' in the final script, but I found this only worked when the iframe height increased in height but not when it decreased in height. [return]
comments powered by Disqus