Combining 'selection' with cell formatting function in a module results in an error
Hello,
When using the following code:
library(shiny)
library(reactable)
testUI <- function(id) {
ns <- NS(id)
tagList(
fluidPage(
titlePanel("row selection example"),
reactableOutput(ns("table")),
verbatimTextOutput(ns("selected"))
)
)
}
testServer <- function(id) {
moduleServer(id,
function(input, output, session) {
ns <- session$ns
selected <- reactive(getReactableState("table", "selected"))
output$table <- renderReactable({
reactable(iris,
selection = "multiple",
onClick = "select" ,
defaultPageSize = 10,
defaultColDef = colDef(
cell = function(x){ifelse(!is.na(x), format(x, digits = 3, nsmall = 3), "")},
filterable = TRUE
)
)
})
output$selected <- renderPrint({
print(selected())
})
observe({
print(iris[selected(), ])
})
})
}
ui <- fluidPage(
testUI('test')
)
server <- function(input, output, session) {
testServer('test')
}
shinyApp(ui, server)
The result is that table does not appear at all.
I get the following error in Chrome's console:

I use the latest CRAN library (0.4.1) with R 4.1.2. Are you aware of this problem?
Hi, thanks for the report, looks like there are at least two issues going on here. One of which is definitely a bug, and the other is possibly a bug, but maybe also partially-intended behavior that should be documented:
- When row selection is enabled, a new column without data is automatically added to the table for the selection checkboxes. This lets you customize a few things like the column width or cell styling, but the
cellrender function essentially does nothing because it's overridden by the selection checkbox/radio. When usingdefaultColDef, the selection column is supposed to be included, but I guess it doesn't make sense to apply thecellrender function to it as well right now. However, it's probable that one day you'd be able to customize the selection cells using thecellrenderer of the selection column, so excluding it indefaultColDefmay not make sense either. At least for now, the selection column is documented, but we could add an additional warning that anything indefaultColDefwill apply to the selection column as well. - There's a bug with rendering multi-length vectors. In the table, it's triggered by trying to render
logical(0), but you can also reproduce it minimally with:
reactable(data.frame(x = TRUE), columns = list(x = colDef(
cell = function() logical(0)
)))
reactable(data.frame(x = TRUE), columns = list(x = colDef(
cell = function() c(1, 2)
)))
With 1 and 2 combined, the errors are happening because the default cell render function is applying to the empty .selection column, and producing logical(0) results because the selection column values are all NULL, and is.na(NULL) produces logical(0) (weird, but that's R).
For now, you can work around this by adding a NULL check to your default cell render function:
defaultColDef = colDef(
cell = function(x) {
if (is.null(x)) return()
ifelse(!is.na(x), format(x, digits = 3, nsmall = 3), "")
},
filterable = TRUE
)
or if you want to do it in the ifelse(), this works too, but is kind of odd to read:
defaultColDef = colDef(
cell = function(x) {
ifelse(isTRUE(!is.na(x)), format(x, digits = 3, nsmall = 3), "")
},
filterable = TRUE
)