The ultimate goal of htmltools is to manipulate, combine and rearrange tags in order to create flexible and rich HTML structures from R. Would you believe that the below example heavily relies on htmltools (Figure 2.1)?
htmltools provides the necessary functions to write HTML tags that were introduced in Chapter 1.3. In R, it is even more convenient than raw HTML since there is no opening/closing tag, a simple function call instead:
Inside the function call, all named elements become attributes, whereas unnamed elements become children. In some cases, tags may have empty attributes like . In that case,the corresponding R code is input(disabled = NA).
Pro tip: Since tag functions produce Shiny tags, that is, HTML elements, calling tag inside a document will render the tag instead of printing its code. Sometimes, particularly in this book, you want to see the code output. In that case, use the code below.You may find another example here.
When building custom templates, you will be writing a lot of tags. It might seemtoo much work to always write tags$. There exists a function called withTags(), which allows you to get rid of all tags$. Hence, the whole code is much easier to write and read:
The first has the shiny.tag.list class in addition to list. You may see it as a detail, but this has noticeable consequences. For instance, tag_list_1 prints as HTML content, whereas tag_list_2 prints as a list. If we try to apply as.character() on both elements, we obtain very different outputs:
Good practice is to check whether the created tag is in line with the HTML validation rules. If you want to check a web page, particularly a Shiny-generated HTML page, W3C has an online validation tool. Be careful, as not following this rule will cause the HTML code to be invalid. By default, Shiny complies with all the recommendations, but we suggest you be careful with any exotic template.
htmltools comes with the HTML() function that you can feed with raw HTML. It prevents HTML escaping on the provided content, which is convenient, for instance, when using formatting tags inside a string:
Interestingly, if you want to convert raw HTML to R code, there is a Shiny App developed by AlanDipert from RStudio, namely html2R, shown Figure 2.3. Non-standard attributes (like data-toggle) are not correctly processed, but there are solutions. This will save you precious time! A more recent approach is developed in Chapter 21 and has been used internally to develop some of the RinteRface templates.
Below we give concrete example on how to customize tags in real life. There exists anice RPG HTML template, that is, rpgui. It providesthe necessary elements to get started developing nice RPG-looking user interfaces, as depicted by Figure 2.4.
In the following, we consider the select input, which does not have exactly the samestructure as the original Shiny tag. However, it is convenient to reuse the Shiny functionsto limit our amount of work. We therefore start to write our custom input:
To fix the first problem we target the outer tag (selectTag), that is, the tag returned by our rpgSelect() function. The second row cleans the label class. The third row removes the extra outer div and only keeps its children, corresponding to the input tag. The last instruction ensures we set the appropriate class, depending on the size value:
These are two lines of code, and believe me, for complex examples, it might be much worse, thereby significantly impairing code readability.Fortunately, htmltools provides powerful functions to overcome this issue, the most significant being reviewed below.
As you may notice, the first approach may lead to poorly written code as soon as thetag structure gets more complex. You may easily end up with things like tag$children[[1]]$children[[2]]$children[[1]]$attribs$class, which is nearly impossible to maintain.The second approach is much more human readable, even though not necessarily shorter in this example.The biggest advantage is that is does not always depend on the overall tag structure. As an exercise, you may wrap the span elements inside another div parent:
Another reason to prefer the new tagQuery() API is the substantial performance gains. Interestingly, under the hood, most if not all older htmltools functions like tagAppendChildren() or tagAppendAttributes() call the tagQuery() API when .cssSelector is provided. In practice,while we can achieve multiple modifications at once with a single tagQuery() call, it requires a combination of multiple tagAppendChildren()/tagAppendAttributes() to reach the same result, thereby leading to less performance.Are you ready to become a tag witcher [^tag-witcher]?
As shown in the preliminary example, the main interest of querying tags is to ultimately modify them. tagQuery() exposes methods to modify attributes, children of the query selection.
You may think it will add each text to the corresponding panel item, but methods like $append() and $prepend() are only able to add the same element(s) to one or multiple target(s). It will actually add three new children to each selected panel. For this case where the content is index specific, we have to utilize $each(). It takes an anonymous function as input, with two parameters. x is the tag and i is the current index. Inside that function, you may edit the tag depending on the index and return the modified structure:
Then we create our custom tag with the .renderHook parameter available for the htmltools tag element, providing a special function, namely a render hook, that will be called upon for tag rendering:
In practice, you will rarely have only one render hook to handle. Most Shiny elements are composedof main wrappers and nested tags. For instance, nav elements like tabsetPanel() and tabPanel() are, again, the perfect example.
The next step is to design the nested item function. The tag consists of asimple div element with a class. In the render hook, we get the theme versionand, depending on the result, we add a child to the item with $append().Note the new-child class. This is the one targeted one level up in my_wrapper_tag().
It is basically a resolve issue. In the top-level render hook, the newly added item is not yet available. To check this, we can put a browser() just before the tagQuery() flow inside my_wrapper_tag():
install.packages("htmltools")
Error in install.packages : Updating loaded packages
install.packages("htmltools")
WARNING: Rtools is required to build R packages but is not currently installed. Please download and install the appropriate version of Rtools before proceeding:
The presence of the path containing 00LOCK is likely a problem. Try uninstalling htmltools. If that (allegedly) succeeds, check to make sure the 00LOCK path no longer exists. If it persists, try deleting it. Once 00LOCK is gone, try installing htmltools again.
Thanks, but in the packages list, htmltools doesn't appear. Is there another way to uninstall it? Also, RTools doesn't appear, but was in another complaint, and I am unable to install it.
UPDATE: Part of the problem appears to be that I need to run RStudio as Administrator.
Are you saying that if (in RStudio) you click on the Packages tab, then click the Install button, then (with the Install from: box set to Repository (CRAN)) type htmltools in the Packages box, it is not listed?
I would suggest shutting down RStudio and restarting it (without loading any scripts or documents) before attempting to install or update any packages, to reduce the likelihood that the package you are updating is already active in memory.
Did you install RTools? Note that RTools is not an R library; it's a separate program, which is apparently need to compile the source code for R libraries. (I'm on Linux, where the tool chain for compiling libraries is already installed.) So you don't install it within RStudio; you download the exe file from the site you linked, run it to install RTools, and then try installing/updating R libraries.
OK, decided to uninstall.reinstall R, to get the 4.3 level. Then downloaded and installed RTools. Then ran RStudio as Admin, and again tried to update rlang, which again failed, again complaining that RTools is not installed. Surely there must be steps which will walk me through this. I am ready to uninstall the whole chain and start over. My confidence in RStudio updates has plummeted.
UPDATE: The short answer, the one that actually solves the problem, is this:
I'm trying to open a new R Markdown document in the RStudio IDE, but it keeps giving me the following message: "Creating R Markdown documents requires updated versions of the following packages: htmltools, rmarkdown. Do you want to install these packages now?"
You opted for the "later source version," it looks like. There's seldom a need to do that and it introduces additional opportunity for trouble. The binary version will have necessarily sorted the compile time dependencies. Try that.
@fgootkind, be aware there are other package repository alternatives that provide precompiled binaries for some Linux distributions. I'm aware of two mainstream options, the public Posit Package Manager and r2u (for the last two Ubuntu LTS releases only) and one option for ARM architectures, the R4Pi Project (currently only for Raspberry Pi OS).
This topic was automatically closed 45 days after the last reply. New replies are no longer allowed.
If you have a query related to it or one of the replies, start a new topic and refer back with a link.
The problem is that since you are using an old R version the latest precompiled binary of htmltools available for it is too old and you don't have RTools properly installed to compile htmltools from source.
This topic was automatically closed 42 days after the last reply. New replies are no longer allowed.
If you have a query related to it or one of the replies, start a new topic and refer back with a link.