How to get a \n newline in table header in blogdown generated html

I am creating a draft website for a work project in blogdown using the default hugo theme (with some modifications) that you can see here: https://betsycc.github.io/OIRA_Web_Reports/databook/2018-enrollment/

I am trying to get the table header to break after the first word in each header cell, so 'Undergraduate', 'Graduate', and 'Total' on top and 'Full-time' 'Part-time and 'Total' underneath.

The header must be one row due to accessibility issues with screenreaders not reading double headers properly, so I cannot otherwise change the header. i.e. each item in the header must be just one cell with no additional header groupings. (I hope that makes sense)

I tried inserting \n, \r, <br/>, &#10; and &#13; into the headers with no success. The first two \n and \r get converted to &#10; and &#13; respectively in the html output but just don't cause the break when published to GitHub pages and viewed in Chrome or Firefox. The third option, <br/>, causes the website not to build. The last two &#10; and &#13; wind up printing the code characters in the header because the ampersand gets converted to &amp;. I tried escaping out the ampersand and that didn't work either although maybe I didn't do that correctly.

Here's what I hope is a good enough minimum reproducible example...?

library(kableExtra)
library(stringr)

data <- data.frame(rbind(c('college1', seq(123, 1145, 147)),
                         c('college2', seq(251, 1573, 192)),
                         c('college3', seq(455, 1777, 189)),
                         c('college4', seq(151, 773, 92))))

# Import headers
head1 <- c("", rep("Undergraduate",3), rep("Graduate",3), "")
head2 <- c("College", rep(c("Full-time", "Part-time", "Total"),2), "Total")

cols <- paste(head1, head2, sep = "\n", collapse = NULL)
cols <- trimws(cols)

# Set headers 
names(data) <- cols

kable(data)

If you knit that and view the html in RStudio's viewer or in a browser it doesn't print the header on two lines. I don't think it's necessary to publish it with blogdown it doesn't seem to work even just as a regular html output. Presumably if I could get this to work it would work in blogdown too.

Good reprex, thanks!

I had a similar problem a few years ago that I described in this post. The specifics are over-elaborate for your purposes.

The key idea is to run your data through xtable() and create two \LaTeX lines (which will properly render in HTML, thanks to pandoc) , one with your top row before the newline and the other the bottom row.

1 Like

Hi @betsyrosalen!

I don't know if you already try, but know that kableExtra as a multi header feature that could help you customize titles for grouped data.

It would look like this:

library(kableExtra)
#> Warning: le package 'kableExtra' a été compilé avec la version R 3.6.2

data <- data.frame(rbind(c('college1', seq(123, 1145, 147)),
                         c('college2', seq(251, 1573, 192)),
                         c('college3', seq(455, 1777, 189)),
                         c('college4', seq(151, 773, 92))))
# Set headers 
names(data) <- c("College", rep(c("Full-time", "Part-time", "Total"),2), "Total")

kable(data, format = "html") %>%
  kable_styling("striped") %>%
  add_header_above(c(" ", "Undergraduate" = 3, "Graduate" = 3, ""))

This is a way to get the information that you want to add without build the string yourself with paste.

Maybe it can help :man_shrugging:

1 Like

Hi @cderv,

Thanks for the suggestion! Unfortunately, I already tried that, but it doesn't work well with screen readers for people with disabilities and that is the main purpose of the project is that it has to be accessible, so I can't use double headers. :frowning_face:

1 Like

Thanks for the suggestion @technocrat! I looked briefly on my phone yesterday and it was a lot to figure out, but I will spend some time on it in the next few days and see if I can get this to work... I'll let you know how it goes!

it is good to know!

When you tried with <br/>, did you think of deactivating the escaping which is by default using kable ?
You need to put escape = FALSE otherwise your html code will be escaped and not apply as html tag.

This works for me in a Rmd to get html document

library(kableExtra)
library(stringr)

data <- data.frame(rbind(c('college1', seq(123, 1145, 147)),
                         c('college2', seq(251, 1573, 192)),
                         c('college3', seq(455, 1777, 189)),
                         c('college4', seq(151, 773, 92))))

# Import headers
head1 <- c("", rep("Undergraduate",3), rep("Graduate",3), "")
head2 <- c("College", rep(c("Full-time", "Part-time", "Total"),2), "Total")

cols <- paste(head1, head2, sep = "<br/>", collapse = NULL)
cols <- trimws(cols)

# Set headers 
names(data) <- cols

kable(data, escape = FALSE)

The table looks like

xtable and other table :package: (huxtable, ...) will for sure be of great help too, but let's just show that kable can do the job too ! :wink:

3 Likes

Interesting! OK, let me see if I can get that to work. I am not actually using kable. I am using a custom function that was written by @dcruvolo so not sure if this will do the trick. I didn't mention the custom function because I wanted to make my reproducible example as simple as possible, so I didn't want to have to put all that code in there too, but I never considered that it would be relevant...

BTW - you can see that function here: Create accessible HTML tables in RStudio?

1 Like

Thanks!

Your current function does currently escape the column names. You need to use htmltools::HTML or shiny::HTML so that your column name are not escape.

Here

    cells <- lapply(1:length(columns), function(n){
        cell <- tags$th(scope="col", htmltools::HTML(columns[n]))
        cell
    })

and here

                cell$children <- list(
                    tags$span(class="hidden-colname", `aria-hidden`="true", HTML(colnames(data)[col])),
                    data[row,col]
                )

This should work. I get that:

3 Likes

Thanks @cderv for the fix! and thanks @dcruvolo for incorporating it into the datatable function so quickly!

You guys Rock! :guitar:

1 Like

In case anyone is interested here is the page I am working on that uses this solution... https://betsycc.github.io/OIRA_Web_Reports/databook/2018-enrollment/

Responsive table formatting and header content on two lines are both all working now!

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.