knitr::opts_chunk$set(echo = TRUE) library(reactable) library(htmltools) propsTable <- function(props) { tags$div( style = "overflow: auto;", tabindex = "0", tags$table( class = "props-tbl", tags$thead( tags$tr( lapply(colnames(props), function(name) tags$th(name)) ) ), tags$tbody( apply(props, 1, function(row) { tags$tr( tags$th(scope = "row", tags$code(row[["Property"]])), tags$td(tags$code(row[["Example"]])), tags$td(row[["Description"]]) ) }) ) ) ) }
You may want to customize how your data is displayed beyond what the built-in formatters provide. For example, inserting a link, combining data from multiple columns, or showing a column total that updates on filtering.
In reactable, you can customize data rendering using either an R or JavaScript function that returns custom content:
R render functions | JavaScript render functions |
---|---|
wzxhzdk:1 | wzxhzdk:2 |
- Easier to use but more static - Render once, when the table is created - Supports [`htmltools`](https://shiny.rstudio.com/articles/tag-glossary.html) and [`htmlwidgets`](https://www.htmlwidgets.org/) | - Harder to use but more dynamic - Render on the fly, based on client-side state - Can be more efficient in large tables |
Whichever one to use depends on the situation and personal preference. You might prefer to use R render functions except in cases where you need more dynamic behavior (e.g., render based on filtered state) or have a very large table.
::: {.callout} This example requires reactable v0.3.0 or above. :::
For example, you can easily add a column total using an R render function:
data <- MASS::Cars93[20:24, c("Manufacturer", "Model", "Type", "Price")] reactable( data, searchable = TRUE, columns = list( Price = colDef(footer = function(values) { htmltools::tags$b(sprintf("$%.2f", sum(values))) }), Manufacturer = colDef(footer = htmltools::tags$b("Total")) ) )
However, the column total doesn't update with filtering. For that, you need a JavaScript render function with access to the client-side filtered state:
data <- MASS::Cars93[20:24, c("Manufacturer", "Model", "Type", "Price")] reactable( data, searchable = TRUE, columns = list( Price = colDef( html = TRUE, footer = JS("function(column, state) { let total = 0 state.sortedData.forEach(function(row) { total += row[column.id] }) return '<b>$' + total.toFixed(2) + '</b>' }") ), Manufacturer = colDef(html = TRUE, footer = "<b>Total</b>") ) )
To customize cell rendering, provide an R function with up to 3 optional arguments:
colDef( cell = function(value, index, name) { # input: # - value, the cell value # - index, the row index (optional) # - name, the column name (optional) # # output: # - content to render (e.g. an HTML tag or widget) htmltools::div(style = "color: red", toupper(value)) } )
Or a JavaScript function, wrapped in JS()
, with up to 2 optional arguments:
colDef( cell = JS(" function(cellInfo, state) { // input: // - cellInfo, an object containing cell info // - state, an object containing the table state (optional) // // output: // - content to render (e.g. an HTML string) return `<div>${cellInfo.value}</div>` } "), html = TRUE # to render as HTML )
With JavaScript functions, you can also customize rendering of grouped cells and aggregated cells:
colDef( grouped = JS("function(cellInfo, state) { return cellInfo.value }"), aggregated = JS("function(cellInfo, state) { return cellInfo.value }") )
cellInfo
propertiescellInfoProps <- dplyr::tribble( ~Property, ~Example, ~Description, "value", '"setosa"', "cell value", "row", '{ Petal.Length: 1.7, Species: "setosa" }', "row data", "column", '{ id: "Petal.Length" }', "column info object", "index", "20", "row index (zero-based)", "viewIndex", "0", "row index within the page (zero-based)", "aggregated", "true", "whether the row is aggregated", "expanded", "true", "whether the row is expanded", "filterValue", '"petal"', "column filter value", "subRows", '[{ Petal.Length: 1.7, Species: "setosa" }, ...]', "sub rows data (aggregated cells only)", "level", "0", "row nesting depth (zero-based)", "selected", "true", "whether the row is selected" ) propsTable(cellInfoProps)
state
propertiesstateProps <- dplyr::tribble( ~Property, ~Example, ~Description, "sorted", '[{ id: "Petal.Length", desc: true }, ...]', "columns being sorted in the table", "page", "2", "page index (zero-based)", "pageSize", "10", "page size", "pages", "5", "number of pages", "filters", '[{ id: "Species", value: "petal" }]', "column filter values", "searchValue", '"petal"', "table search value", "selected", '[0, 1, 4]', "selected row indices (zero-based)", "pageRows", '[{ Petal.Length: 1.7, Species: "setosa" }, ...]', "current row data on the page", "sortedData", '[{ Petal.Length: 1.7, Species: "setosa" }, ...]', "current row data in the table (after sorting, filtering, grouping)", "data", '[{ Petal.Length: 1.7, Species: "setosa" }, ...]', "original row data in the table", "meta", '{ custom: 123 }', tagList("custom table metadata from", tags$code("reactable()"), "(new in v0.4.0)"), "hiddenColumns", '["Petal.Length"]', "columns being hidden in the table" ) propsTable(stateProps)
To customize header rendering, provide an R function with up to 2 optional arguments:
colDef( header = function(value, name) { # input: # - value, the header value # - name, the column name (optional) # # output: # - content to render (e.g. an HTML tag or widget) htmltools::div(value) } )
Or a JavaScript function with up to 2 optional arguments:
colDef( header = JS(" function(column, state) { // input: // - column, an object containing column properties // - state, an object containing the table state (optional) // // output: // - content to render (e.g. an HTML string) return `<div>${column.name}</div>` } "), html = TRUE # to render as HTML )
column
propertiescolumnProps <- dplyr::tribble( ~Property, ~Example, ~Description, "id", '"Petal.Length"', "column ID", "name", '"Petal Length"', "column display name", "filterValue", '"petal"', "column filter value", "setFilter", 'function setFilter(value: any)', tagList("function to set the column filter value", "(set to ", tags$code("undefined"), " to clear the filter)"), "column", '{ id: "Petal.Length", name: "Petal Length", filterValue: "petal" }', "column info object (deprecated in v0.3.0)", "data", '[{ Petal.Length: 1.7, Petal.Width: 0.2, _subRows: [] }, ...]', "current row data in the table (deprecated in v0.3.0)" ) propsTable(columnProps)
state
propertiespropsTable(stateProps)
To add footer content, provide an R function with up to 2 optional arguments:
colDef( footer = function(values, name) { # input: # - values, the column values # - name, the column name (optional) # # output: # - content to render (e.g. an HTML tag or widget) htmltools::div(paste("Total:", sum(values))) } )
Or a JavaScript function with up to 2 optional arguments:
colDef( footer = JS(" function(column, state) { // input: // - column, an object containing column properties // - state, an object containing the table state (optional) // // output: // - content to render (e.g. an HTML string) return `<div>Rows: ${state.sortedData.length}</div>` } "), html = TRUE # to render as HTML )
column
propertiespropsTable(columnProps)
state
propertiespropsTable(stateProps)
To add expandable row details, provide an R function with up to 2 optional arguments:
reactable( details = function(index, name) { # input: # - index, the row index # - name, the column name (optional) # # output: # - content to render (e.g., an HTML tag or nested table), or NULL to hide details htmltools::div( paste("Details for row:", index), reactable(data[index, ]) ) } )
Or a JavaScript function with up to 2 optional arguments:
reactable( details = JS(" function(rowInfo, state) { // input: // - rowInfo, an object containing row info // - state, an object containing the table state (optional) // // output: // - content to render (e.g. an HTML string) return `<div>Details for row: ${rowInfo.index}</div>` } ") )
rowInfo
propertiesrowInfoProps <- dplyr::tribble( ~Property, ~Example, ~Description, "values", '{ Petal.Length: 1.7, Species: "setosa" }', "row data values", "row", '{ Petal.Length: 1.7, Species: "setosa" }', tagList("same as ", tags$code("values"), " (deprecated in v0.3.0)"), "index", "20", "row index (zero-based)", "viewIndex", "0", "row index within the page (zero-based)", "expanded", "true", "whether the row is expanded", "level", "0", "row nesting depth (zero-based)", "selected", "true", "whether the row is selected" ) propsTable(rowInfoProps)
state
propertiespropsTable(stateProps)
```{css echo=FALSE} / rmarkdown html documents / .main-container { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; }
.main-container blockquote { font-size: inherit; } ```
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.