Create accessible HTML tables in RStudio?

I am trying to find tools to generate accessible html tables with all the proper tagging per WCAG 2.1 standards from R data frames. I found this tool online that is somewhat helpful: HTML Table Generator because I can always export the tables to csv and then drag and drop them in there, but the problem is that the reports I need to recreate have multiple headers and other more complex formats that can't be generated by that tool. Specifically I have a lot of tables like the ones described here: Tables with irregular headers.

The other major challenge that makes this so difficult to do in R is that I need to be able to just copy and paste the HTML into WordPress since that is what the organization I work for uses for it's website. I tried using various packages for formatting tables (kableExtra, DT, xtable, etc..) but the problem is that the HTML that is generated goes completely wonky when pasted into WordPress. All of the Bootstrap/CSS styling is removed by WordPress. What I really need is just simple 'clean' html tables without all that extra styling so that WordPress can just apply the standard CSS for my org.

Does anyone know of any tools/packages that I can use to generate theses tables? There are literally dozens of these tables that are generated repeatedly at different times of the year, so I need something that automates the process as much as possible.

If there are no existing packages that can do this I thought maybe I can try to write one! But sadly, I don't have any idea where to start. So any helpful advice for strategies to create something like this would be appreciated as well!

The following is assuming that html files are generated from rmarkdown (.rmd) files. Rendering html from rmarkdown uses the rmarkdown package.

Remove CSS

Setting theme to null in header (front matter) of rmarkdown file per the documentation should remove the bootstrap css. Alternatively, you can specify your own css to be included if you like.

title: "Lorem Ipsum"
    theme: null

Changing the tags: Use a different pandoc template.

If just removing the css was insufficient, you should be able to change the html tags to whatever suits you by creating your own pandoc template. You can change the template used by pandoc as per documentation

    template: template.html

Looking at the call made to pandoc to produce the html, you can see that the template used comes from the rmarkdown package. It might be worth using that as a starting point for constructing your own custom template.

--template /YOUR/RLIBSPATH/rmarkdown/rmd/h/default.html

Keep the intermediate markdown

It might be useful to keep the intermediate markdown file when working on your own pandoc template. You can keep the markdown generated to be passed to pandoc by setting the keep_md in the header (front matter) of your rmarkdown.

title: "Something fascinating"
    keep_md: TRUE

Hope this was helpful.

Hi @betsyrosalen,

It is early days, but I'm in the planning phase of creating a package or a collection of accessible UI components for shiny. (I'm looking for collaborators too!)

The first element I've worked on is a responsive, accessible data table component. The challenge, as you stated, was to make to produce a function that follows good accessible practices and semantic html rules. I also wanted the ability to add attributes for scope when applicable and make it possible to add stricter levels of accessibility for complex layouts (this part is still ongoing). The function datatable produces a a table that follows good accessibility guidelines and semantic HTML practices.

Behind the scenes, there are two helper functions that generate the html markup for the table header and the table body. To make the table more accessible, the header function adds the attribute scope="col" to all headers. The body function renders the first column of every as a header and adds the attribute scope="row". However, this is assuming that the first column contains header information that corresponds to the entire row. I'm still thinking of a more appropriate method for turning this aspect off. If supplied, the function also renders a caption to the table and adjusts aria-* attributes as necessary.

Here's an example using the first two rows iris dataset. You can ignore the data-colname attribute I'm still working on this part.

# in r
datatable(data = iris[1:2,], id="iris", caption = "Iris Dataset")
<table class="datatable" id="datatable-iris" aria-labelledby="datatable-iris-caption">
  <caption id="datatable-iris-caption">Iris Dataset</caption>
      <th scope="col">Sepal.Length</th>
      <th scope="col">Sepal.Width</th>
      <th scope="col">Petal.Length</th>
      <th scope="col">Petal.Width</th>
      <th scope="col">Species</th>
      <th scope="row" data-colname="Sepal.Length">5.1</th>
      <td data-colname="Sepal.Width">3.5</td>
      <td data-colname="Petal.Length">1.4</td>
      <td data-colname="Petal.Width">0.2</td>
      <td data-colname="Species">setosa</td>
      <th scope="row" data-colname="Sepal.Length">4.9</th>
      <td data-colname="Sepal.Width">3</td>
      <td data-colname="Petal.Length">1.4</td>
      <td data-colname="Petal.Width">0.2</td>
      <td data-colname="Species">setosa</td>

Hope that helps!

(Here's the link to the function:


I forgot how to save the html markup. Here's a short example

t <- datatable(data = iris, id="iris", caption = "Iris Dataset")
writeLines(as.character(t), "~/Desktop/iris_datatable.html")
1 Like

Hi @grosscol!

Thanks for the suggestions. I already tried using custom CSS and setting the theme to NULL, but neither of those actually removes all the styling in the html code that is output. I also started looking into creating a custom pandoc template, but really struggled to understand the documentation on how to go about doing that, but it is something that I plan to look into some more...

What I just found a few minutes ago (that I still can't believe was so difficult to find) is that there is an output type called "html_fragment" that does the trick of removing all the extra styling! It doesn't have all the proper scope attributes that dcruvolo mentions below, but it's better than what I was working with before!

All I had to do was put this in the yaml at the top of the file:

1 Like

Hi @dcruvolo!

Thank you so much! I just tested it out and that is fantastic! I can't thank you enough! I would LOVE to help with this project if I am able, but might need some mentoring to figure out what I need to learn to have the skills needed to be useful.

So just making sure I understand that it does not yet support multiple headers rows. Only single headers at the moment. right? Still pretty fantastic and light years better than anything else I have found so far.

BTW I am also still learning about accessibility, so just recently heard about aria-* attributes and figuring out what those are too...

Good to hear the script is useful! Yes, the component is still under development. I am working on adding more rendering options and supporting different layouts, as well as adding options for responsive layouts. Most of my projects require summary tables and very rarely I use complex table layouts (e.g., grouped columns or rows, nested tables, etc.). I try avoid these layouts where possible as it is difficult to make the tables accessible. It is not impossible, but it requires extensive testing with a screen reader and a lot of time to develop. Stay tuned!

I am excited to hear that you are interested in the project. I do not have an idea on how the best method for starting the project. Most of the planning has been mainly in form of thoughts. Perhaps a GitHub repository would work?

I will say that the most important step for learning accessibility is to learn semantic HTML or the proper use of tags to structure web documents. Well structured documents are far better than using aria attributes. However, there are times that aria attributes should be used. There are a lot of resources for learning accessibility. I have provided a few resources for getting started. Unfortunately, there are little to no resources for R and shiny developers, but this will change!

@dcruvolo thanks! I just spent some more time looking at your datatables function code and I think I get the gist of how it works, but I am still not clear about how Shiny is involved. Guess I need to study up on Shiny... I can start with your tutorials! :slight_smile: I'm assuming that Shiny is what turns all the tags$ parts into HTML? We can take the conversation over to GitHub if you like. I would definitely like to see if I can help add more features and turn your function into an R package!

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