# widgetframe and knitr

## knitr

The knitr package, along with the rmarkdown package converts a R markdown (Rmd) document into a target document, which can be an HTML Document, a HTML Website, a Dashboard, or a PDF/Word Document etc.

widgetframe is designed to be used in Rmd documents which will eventually be knitted to an HTML or a derived format. There is little or no benefit in using widgetframe::frameWidget() when the output format is not HTML based such as PDF, Microsoft Word etc. In fact widgetframe will most definitely not work for such output formats.

## Regular htmlwidgets and knitr

By default when knitting htmlwidgets the htmlwidgets:::knit_print.htmlwidgets() function (an internal function exposed as an S3 method) is called. The output of this call is a list containing the HTML code + a list of HTML dependencies (JS/CSS) required to render the widget. How this is then inserted into the final document depends on the output format. For this discussion we are going to limit to HTML based output formats because as noted above widgetframe is designed to work only for HTML based output formats.

Let’s start with the simplest of HTML output format rmarkdown::html_document(). The self_contained (default = TRUE), and the lib_dir (default = name of document + _files) arguments of this output format dictate how htmlwidgets instances appear in the final document. If self_contained is TRUE then the HTML dependencies (JS/CSS) are all inlined and the result is just one single HTML document. Naturally this document is quite large in size due to the dependencies being inlined. If self_contained is FALSE then the HTML dependencies are kept in a separate directory determined by the lib_dir argument. Other HTML based formats like bookdown, flexdashboard etc. too have similar arguments. This is not surprising as they tend to extend rmarkdown::html_document.

### Potential Issues

Unless you are working on small one-off Rmd document, it is never a good idea to have self_contained set to its default value TRUE. It results in large HTML documents which are slow to load in the browser. Secondly by inlining dependencies you lose the ability to share common dependencies across different HTMLs. Lastly you also limit the browser’s ability to cache HTML dependencies across sessions.

Even if you were to externalize the dependencies by setting sefl_contained=FALSE, there are still two potential issues…

• Different htmlwidgets may depend on different versions of the same Javascript/CSS dependency. But when the final document is produced only a single version of the said dependency is used. This may cause certain widgets to not display, or work incorrectly.
• The styling rules (CSS) of the widget may be overridden by those of the output format. This will again result in the widget not displaying properly in the final document.

These problems typically don’t occur when knitting one-off HTML documents using the rmarkdown::html_document format. But they do occur once you start outputting documents in the bookdown, blogdown, rmarkdown websites, xaringan and other HTML based output formats. And this is where widgetframe comes in.

## widgetframe

widgetframe is itself a htmlwidgets instance, but of a different kind. Instead of wrapping a Javascript based dataviz object, it wraps another htmlwidgets instance like leaflet, or DT, or dygraphs etc. It does so by embedding the target htmlwidgets instance in a HTML iframe. It also uses NPR’s pym.js Javascript library to make the iframes responsive. This allows you to easily embed htmlwidgets inside complex HTML documents and avoid the issues mentioned in the section above.

## widgetframe and knitr

To understand how the knitting of widgetframes differ from regular htmlwidgets, let’s examine the following code. It shows you how to use widgetframe::fameWidget() function in a RMarkdown document and the three knitr chunk options it supports.

{r, include=FALSE}

# widgetframe supports 3 custom knitr chunk options...

# For all practicle purposes this should always be FALSE
knitr::opts_chunk$set(widgetframe_self_contained = FALSE) # default = FALSE # For all practicle purposes this should always be TRUE knitr::opts_chunk$set(widgetframe_isolate_widgets = TRUE) # default = TRUE

# Only needed in bookdown format/s such as bookdown::gitbook. Otherwise don't set.

## widgetframe and bookdown

For the bookdown output format, we need some additional steps to correctly use widgetframes. This section describes those steps.

1. The default output directory of the bookdown book is _book, which can be configured via _bookdown.yml file.

2. For the bookdown::gitbook format we need to explicitly set the widgetframe_widgets_dir to some value (e.g. ‘widgets’), so that the embedded widgets HTML code is saved in this directory instead of the default.

3. After 'bookdown::render_book("index.Rmd") has been called, we need to move the widgets directory inside the final output directory.

You can easily use a Makefile for this. e.g.

Your _bookdown.yml file

output_dir: "book"

and your Makefile

book: index.Rmd
Rscript -e 'bookdown::render_book("index.Rmd")'
mv widgets book/.

and inside index.Rmd you should have something like

{r, include=FALSE}
knitr::opts_chunk\$set(widgetframe_widgets_dir = 'widgets' )