rshinydt

Add vertical line in a DT datatable in a shiny app with custom container


I want to add a vertical line between groups of columns. Here is a desired outcome:

---------
g1  | g2
---------
a b | a b
---------
1 2 | 3 4
---------

and a shiny app to start with:

library(shiny)
library(DT)
library(htmltools)

runApp(shinyApp(
  ui <- basicPage(
    DT::dataTableOutput('table1')
  ),
  server = function(input, output) {
    output$table1 <- DT::renderDataTable({
      datatable(data.frame(a1 = 1, b1 = 2, a2 = 3, b2 = 4), rownames = FALSE,
                container = withTags(table(
                  class = 'display',
                  thead(
                    tr(
                      th(colspan = 2, 'g1'),
                      th(colspan = 2, 'g2')
                    ),
                    tr(
                      lapply(rep(c('a', 'b'), 2), th)
                    )
                  )
                ))
      )
    })
  }
))

Current output from shiny app above:

enter image description here


Solution

  • You could add a css class that adds a border on the right of the cells and apply it to the relevant columns using the columnDefs options. For the header, you can set the class using the initComplete callback.

    Here's an example:

    library(shiny)
    library(DT)
    library(htmltools)
    
    runApp(shinyApp(
      ui <- basicPage(
        tags$head(
          tags$style(HTML(".cell-border-right{border-right: 1px solid #000}"))),
        DT::dataTableOutput('table1')
      ),
      server = function(input, output) {
        output$table1 <- DT::renderDataTable({
          datatable(data.frame(a1 = 1, b1 = 2, a2 = 3, b2 = 4), rownames = FALSE,
                    container = withTags(table(
                      class = 'display',
                      thead(
                        tr(
                          th(colspan = 2, 'g1'),
                          th(colspan = 2, 'g2')
                        ),
                        tr(
                          lapply(rep(c('a', 'b'), 2), th)
                        )
                      )
                    )),options = list(initComplete = JS(
                      "function(settings, json) {",
                      "var headerBorder = [0,1];",
                      "var header = $(this.api().table().header()).find('tr:first > th').filter(function(index) {return $.inArray(index,headerBorder) > -1 ;}).addClass('cell-border-right');",
                      "}"),columnDefs=list(list(className="dt-right cell-border-right",targets=1))
          ))
        })
      }
    ))
    

    The jquery selectors are used to select the first row of the header and the first th tag, so that the border is only added to the g1 cell.