How to conditionally format multiple columns and specific rows in reactable table?

148 views Asked by At

I have some example data below where I'm trying to conditionally format all numeric columns in my reactable table but only for row 1. For example, I'd like to use a traffic light system and assign the cell backgrounds in row 1 as green, red or orange if the value is more than that in row 2, within 10% of row 2 or more than 10% below the values in row 2, respectively.

library(reactable)

set.seed(1)
name <- c("Player A", "Player B", "Team")
var1 <- rnorm(3, 1000, 200)
var2 <- rnorm(3, 1000, 200)
var3 <- rnorm(3, 1000, 200)

d <- data.frame(name, var1, var2, var3)

reactable(d,
          defaultColDef = colDef(
            align = "center",
            format = colFormat(digits = 1)
          )
          )

I'm familiar with something like the below code, but I'm not sure how I can apply something like this to only specific rows and for multiple columns without repeating the function several times in colDef().

reactable(sleep[1:6, ], columns = list(
  extra = colDef(
    style = function(value) {
      if (value > 0) {
        color <- "#008000"
      } else if (value < 0) {
        color <- "#e00000"
      } else {
        color <- "#777"
      }
      list(color = color, fontWeight = "bold")
    }
  )
))
1

There are 1 answers

3
stefan On BEST ANSWER

Here is one option to achieve your desired result which uses the row index passed to the style function as a second argument to access the value of the successor row. Additionally I use lapply to create the colDefs for a list of column names.

library(reactable)

style_fun <- function(.data, colname) {
  function(value, index) {
    if (index < 2) {
      successor_value <- .data[[colname]][index + 1]
      if (value > successor_value) {
        color <- "#008000"
      } else if (value >= .9 * successor_value) {
        color <- "orange"
      } else if (value < .9 * successor_value) {
        color <- "#e00000"
      } else {
        color <- "#777"
      }
      return(
        list(color = color, fontWeight = "bold")
      )
    } else {
      return(NULL)
    }
  }
}

cols <- names(d)[-1]
col_defs <- lapply(
  cols, function(x)
  colDef(
    style = style_fun(d, x)
  )
) 
names(col_defs) <- cols

reactable(d,
  defaultColDef = colDef(
    align = "center",
    format = colFormat(digits = 1)
  ),
  columns = col_defs
)

enter image description here