Customising the colour and transparency of a selected row in conditionally-formatted DT::datatable in a shiny app

145 views Asked by At

I need to display a table in a Shiny app with the following requirements:

  • app uses bslib themes (important because changes the css needed)
  • table has conditional formatting (colours representing numeric values)
  • the ability to select one or more rows in table
  • when a row is selected, you can still see the conditional formatting

The default settings for datatable do not enable the last point - when you select a row, the selection colour is opaque and on top of the conditional formatting.

In contrast, a package like rhandsontable takes an excel-like approach where the selected row is indicated with a semi-transparent colour.

I can't use rhandsontable for other reasons, and I also cannot use the formattable package, because it (at present) converts numeric values into strings which prevents sorting the table by header correctly (see the github issue). So I am using DT's built-in conditional formatting functions (formatStyle, styleInterval).

Here's a minimal app that meets all the requirements, but there's something weird going on with the colour of the row selection and I'd like to understand it.

library(shiny)
library(dplyr)

ui <- bslib::page_fluid(
  theme = bslib::bs_add_rules(
    bslib::bs_theme(),
    sass::as_sass("table.dataTable tbody tr.active td {
             color: black !important;
             box-shadow: inset 0 0 0 9999px rgba(255, 255, 0, 0.2) !important;}"
    )),
  DT::dataTableOutput("test_table")
)

server <- function(input, output, session) {

  iris_small = iris %>% dplyr::slice_sample(n = 10)

  output$test_table <- DT::renderDataTable({

    cols_to_format <- c("Sepal.Length", "Sepal.Width", "Petal.Length", "Petal.Width")

    # create 19 breaks and 20 rgb color values ranging from white to red
    brks <- quantile(iris_small[cols_to_format], probs = seq(.05, .95, .05), na.rm = TRUE)
    clrs <- round(seq(255, 40, length.out = length(brks) + 1), 0) %>%
      {paste0("rgb(255,", ., ",", ., ")")}

    iris_dt <- DT::datatable(
      iris_small,
      selection = 'multiple',
      class = "hover row-border order-column compact nowrap",
    )

    iris_dt <- iris_dt %>%
      DT::formatStyle(
        cols_to_format,
        target = "cell",
        backgroundColor = DT::styleInterval(brks, clrs)
      )

    iris_dt
  })
}

shinyApp(ui, server = server)

I have chosen to conditionally format the cells from white to red based on their value (guided by this example).

To change the colour of the selected row, I have used a bit of css guided by the kind person who answered a previous question. Here, I have modified the css to use the rgba() function add transparency so the conditional formatting can still be seen.

For the conditionally-formatted columns this works well.

But for the row numbers, and any columns that are not formatted, the transparent yellow colour indicating a row selection appears to overlap a blue colour.

enter image description here

I am not sure how to figure out where this blue colour comes from, and how to remove it. I can see that box-shadow is the property to set the colour of the selected row. I also tried adjusting the background-color property, this doesn't work (doesn't go transparent). I am fairly new to css and I don't know how to find what other property might be causing this blue colour to appear.

I can work around this (by turning off row names and by setting all cells to a white background with formatStyle before applying the conditional formatting), but I wanted to ask this question here because:

  1. I'd like to understand why it's happening and how to fix it, and also
  2. although there are related questions here and here, I have not seen an example available showing how to create a transparent row selection for a conditionally-formatted DT table, and I thought it might be a useful reference
0

There are 0 answers