1

I'm unsuccessfully trying to set the font color for flextable generated in r markdown using a css stylesheet.

I can accomplish this when I turn off shadow host, but not with it on. (Just turning it off removes other desirable features.) Here's a short r markdown file demonstrating the difference.


---
title: "Untitled"
output: html_document
---

<style>
div.flextable-shadow-host * {
  color: pink;
}

div.tabwid * {
  color: pink;
}

</style>

# ignores CSS above

```{r, echo=FALSE}
library(flextable)
flextable(head(mtcars))
```

# accepts CSS above

```{r, echo=FALSE}
ft <- flextable(head(mtcars))
htmltools_value(ft, ft.shadow = FALSE)
```


I want the css external to the r code because I have a button selector on the website the user can change the overall style (e.g., dark mode or not).

ssp3nc3r
  • 3,662
  • 2
  • 13
  • 23
  • Inspecting the html file, the flextable shadow does state indicate it's "open", and this stack overflow post suggests what I'm trying to accomplish is possible: https://stackoverflow.com/questions/47625017/override-styles-in-a-shadow-root-element but I'm not that familiar with shadow trees. – ssp3nc3r Jan 31 '22 at 21:36

1 Answers1

3

When using shadow, the table is assembled outside of HTML. Only the id connects the table to HTML. However, flextable has functions for setting the color. Why not just use one of the many built-in methods to change the color?

For example:

# ignores CSS above

```{r liberator,include=F}
library(flextable)
library(tidyverse)

```

```{r tbler, echo=FALSE}

flextable(head(mtcars)) %>% 
  color(color = "pink", part = "all")

```

# accepts CSS above

```{r, echo=FALSE}
ft <- flextable(head(mtcars))
htmltools_value(ft, ft.shadow = FALSE)
```

enter image description here

There are many things you can do with flextable styling. You can see more customization options here.



Update: Based on your comments

Okay, this works to change the color of a flextable.

This works if there is only one flextable in the script.

I have the color of the text set to #b21E29 (a shade of red). You can change that as you see fit.

These will SKIP non-shadow flextables

Add this chunk anywhere in your RMD script. This requires no additional libraries or any other customization in your R code.

```{r js_ing,results="asis",engine="js",echo=F}
// extract the styles that are set for the flextable
letMe = document.querySelector('div.flextable-shadow-host').shadowRoot.querySelector('div>style');

// replace color style
// preceding ';' so that 'background-color' doesn't change
letMe.innerHTML = letMe.innerHTML.replace(/;(color:.+?);/g, ';color:#b21e29 !important;');                
```

enter image description here

If you have more than one flextable with shadow on, you can use one of the two following chunks instead. In the first--all the same color; in the second--each table has a different color.

These work if there is more than one flextable in the script.

Pay attention to the comments so you can see what to use when depending on your desired output.

All the same color:

```{r moreJs_ing,results="asis",engine="js",echo=F}
// collect all of the flextables with shadow
letMe = document.querySelectorAll('div.flextable-shadow-host');

// to set all shadow flextables to the same font color:
for(i = 0, n = letMe.length; i < n; i++){
  showMe = letMe[i].shadowRoot.querySelector('div>style');
  showMe.innerHTML = showMe.innerHTML.replace(/;(color:.+?);/g, ';color:#b21e29 !important;');
}
```

enter image description here

Each with there own color:

```{r evenMoreJs_ing,results="asis",engine="js",echo=F}
//alternatively to set each to a different color
// make sure you only include one of these options!

// collect all of the flextables with shadow
letMe = document.querySelectorAll('div.flextable-shadow-host');

// first table in script
showFirst = letMe[0].shadowRoot.querySelector('div>style');
showFirst.innerHTML = showFirst.innerHTML.replace(/;(color:.+?);/g, ';color:#b21e29 !important;');

// second table in script
showSecond = letMe[1].shadowRoot.querySelector('div>style');
showSecond.innerHTML = showSecond.innerHTML.replace(/;(color:.+?);/g, ';color:#003b70 !important;');


// change the indices for each table, keep in mind the first table is [0], not [1]
```

enter image description here

If you aren't sure where you want to go with these, add all three and and include=F as a chunk option to the two you aren't using at that moment in time.

Kat
  • 15,669
  • 3
  • 18
  • 51
  • Hi Kat, I need to be able to change the color after the html file is loaded based on a styling button that the user selects (e.g., changing to dark mode from regular: white background with black text changes to black background with white text), so using the built-in flextable function as you suggested won't work for dynamic changes. – ssp3nc3r Jan 31 '22 at 16:07
  • Sorry for the delay; I missed the update, but thanks! I was able to use your js to get the effect I wanted, but it seems there should be a way to use straight css instead of a js selector, no? – ssp3nc3r Feb 16 '22 at 01:33
  • 1
    Not in this case. There are at least two reasons: the styles are initially established with JS, and the content is a shadow. Think of it as a webpage within a webpage. Glad I could help! – Kat Feb 16 '22 at 02:12