Skip to content

Global Filtering for Main and Nested Tables without Hidden Columns Using JavaScript API #409

@sciordia

Description

@sciordia

Hi @glin,

I'm currently building a Shiny application using the reactable package where the main table displays data and, upon clicking a row, a nested subtable (details) is revealed. My objective is to implement a single global search field that filters both the main table and its nested subtable. I’ve explored using a hidden column that consolidates the nested data into the main table, but I find it to be a workaround rather than an ideal solution.

I reviewed the code provided in [Issue #225](#225), yet I'm wondering if there’s a simpler or more direct approach using the reactable JavaScript API that allows searching across fields in both the main table and the nested subtable without resorting to hidden columns. Is there a built-in option or a recommended method to achieve this global filtering functionality for nested tables?

This is an example code:

library(shiny)
library(reactable)
library(dplyr)
library(htmltools)

# Example data frames
df1 <- data.frame(
  ID = c("A1", "A2", "A3"),
  Name = c("Jim", "Mary", "Peter"),
  Value = c(10, 20, 30),
  stringsAsFactors = FALSE
)

df2 <- data.frame(
  ID = c("A1", "A1", "A2", "A3", "A3"),
  Description = c("Item 1", "Item 2", "Detail for A2", "Detail X", "Detail Y"),
  Quantity = c(5, 7, 15, 25, 35),
  stringsAsFactors = FALSE
)

# Add a hidden column to df1 with concatenated information from df2
df_main <- df1 %>%
  left_join(
    df2 %>%
      group_by(ID) %>%
      summarise(Details = paste(paste0(Description, " (", Quantity, ")"), collapse = ", ")),
    by = "ID"
  )

ui <- fluidPage(
  # Page title
  titlePanel("Main Table with Nested Subtable and Global Search"),
  
  # Single search box to filter the main table (which includes the hidden field)
  div(
    tags$input(
      id = "search_input",
      type = "search",
      placeholder = "Search in both levels...",
      # The search is applied to the main table whose elementId is "main_table"
      oninput = "Reactable.setSearch('main_table', this.value)"
    )
  ),
  
  # Main table output
  reactableOutput("main_table")
)

server <- function(input, output, session) {
  
  output$main_table <- renderReactable({
    reactable(
      df_main,
      elementId = "main_table",  # ID to be used with the JavaScript API
      searchable = FALSE,        # Use external JS search
      defaultPageSize = 5,
      pagination = TRUE,
      columns = list(
        ID = colDef(name = "ID", align = "center", width = 80),
        Name = colDef(name = "Name"),
        Value = colDef(name = "Value", align = "center"),
        # Hidden column: it remains in the data frame for search purposes,
        # but is hidden via CSS.
        Details = colDef(
          style = list(display = "none"),
          headerStyle = list(display = "none")
        )
      ),
      # Define the details (nested subtable) shown when a row is clicked
      details = function(index) {
        # Filter df2 to get records with an ID matching the selected row
        subdata <- df2 %>% filter(ID == df_main$ID[index])
        if (nrow(subdata) == 0) return(NULL)
        # Create the nested subtable using reactable.
        reactable(
          subdata,
          searchable = FALSE,
          pagination = FALSE,
          columns = list(
            ID = colDef(name = "ID", align = "center", width = 60),
            Description = colDef(name = "Description"),
            Quantity = colDef(name = "Quantity", align = "center")
          )
        )
      }
    )
  })
}

shinyApp(ui, server)

Thank you in advance for your guidance.

Best regards,
Sergio

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions