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 |
---|---|
|
|
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.
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) {
const values = state.data.map(function(row) {
return row[column.id]
})
let total = 0
values.forEach(function(value) {
total += value
})
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:
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, new in v0.3.0)
//
// 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
properties
Property | Example | Description |
---|---|---|
value
|
"setosa"
|
cell value |
row
|
{ Petal.Length: 1.7, Species: "setosa" }
|
row data values |
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 (new in v0.3.0) |
filterValue
|
"petal"
|
column filter value (new in v0.3.0) |
subRows
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
array of sub row data values (aggregated cells only) |
level
|
0
|
row nesting depth (zero-based) |
selected
|
true
|
whether the row is selected (new in v0.3.0) |
state
properties
Property | Example | Description |
---|---|---|
sorted
|
[{ id: "Petal.Length", desc: true }, ...]
|
array of columns being sorted in the table |
page
|
2
|
page index (zero-based, new in v0.3.0) |
pageSize
|
10
|
page size (new in v0.3.0) |
pages
|
5
|
number of pages (new in v0.3.0) |
filters
|
[{ id: "Species", value: "petal" }]
|
array of column filter values (new in v0.3.0) |
searchValue
|
"petal"
|
table search value (new in v0.3.0) |
selected
|
[0, 1, 4]
|
array of selected row indices (zero-based, new in v0.3.0) |
pageRows
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
array of row data values in the page |
sortedData
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
sorted array of row data values in the table |
data
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
original array of row data values in the table |
To customize header rendering, provide an R function with up to 2 optional arguments:
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, new in v0.3.0)
//
// output:
// - content to render (e.g. an HTML string)
return '<div>' + column.name + '</div>'
}
"),
html = TRUE # to render as HTML
)
column
properties
Property | Example | Description |
---|---|---|
id
|
"Petal.Length"
|
column ID (new in v0.3.0) |
name
|
"Petal Length"
|
column display name (new in v0.3.0) |
filterValue
|
"petal"
|
column filter value (new in v0.3.0) |
setFilter
|
function setFilter(value: any)
|
function to set the column filter value
(set to
undefined
to clear the filter) (new in v0.3.0)
|
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: [] }, ...]
|
sorted array of row data values in the table (deprecated in v0.3.0) |
state
properties
Property | Example | Description |
---|---|---|
sorted
|
[{ id: "Petal.Length", desc: true }, ...]
|
array of columns being sorted in the table |
page
|
2
|
page index (zero-based, new in v0.3.0) |
pageSize
|
10
|
page size (new in v0.3.0) |
pages
|
5
|
number of pages (new in v0.3.0) |
filters
|
[{ id: "Species", value: "petal" }]
|
array of column filter values (new in v0.3.0) |
searchValue
|
"petal"
|
table search value (new in v0.3.0) |
selected
|
[0, 1, 4]
|
array of selected row indices (zero-based, new in v0.3.0) |
pageRows
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
array of row data values in the page |
sortedData
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
sorted array of row data values in the table |
data
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
original array of row data values in the table |
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, new in v0.3.0)
//
// output:
// - content to render (e.g. an HTML string)
return '<div>Rows: ' + state.data.length + '</div>'
}
"),
html = TRUE # to render as HTML
)
column
properties
Property | Example | Description |
---|---|---|
id
|
"Petal.Length"
|
column ID (new in v0.3.0) |
name
|
"Petal Length"
|
column display name (new in v0.3.0) |
filterValue
|
"petal"
|
column filter value (new in v0.3.0) |
setFilter
|
function setFilter(value: any)
|
function to set the column filter value
(set to
undefined
to clear the filter) (new in v0.3.0)
|
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: [] }, ...]
|
sorted array of row data values in the table (deprecated in v0.3.0) |
state
properties
Property | Example | Description |
---|---|---|
sorted
|
[{ id: "Petal.Length", desc: true }, ...]
|
array of columns being sorted in the table |
page
|
2
|
page index (zero-based, new in v0.3.0) |
pageSize
|
10
|
page size (new in v0.3.0) |
pages
|
5
|
number of pages (new in v0.3.0) |
filters
|
[{ id: "Species", value: "petal" }]
|
array of column filter values (new in v0.3.0) |
searchValue
|
"petal"
|
table search value (new in v0.3.0) |
selected
|
[0, 1, 4]
|
array of selected row indices (zero-based, new in v0.3.0) |
pageRows
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
array of row data values in the page |
sortedData
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
sorted array of row data values in the table |
data
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
original array of row data values in the table |
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 for the row
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, new in v0.3.0)
//
// output:
// - content to render (e.g. an HTML string)
return '<div>Details for row: ' + rowInfo.index + '</div>'
}
")
)
rowInfo
properties
Property | Example | Description |
---|---|---|
values
|
{ Petal.Length: 1.7, Species: "setosa" }
|
row data values (new in v0.3.0) |
row
|
{ Petal.Length: 1.7, Species: "setosa" }
|
same as
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 (new in v0.3.0) |
level
|
0
|
row nesting depth (zero-based) |
selected
|
true
|
whether the row is selected |
state
properties
Property | Example | Description |
---|---|---|
sorted
|
[{ id: "Petal.Length", desc: true }, ...]
|
array of columns being sorted in the table |
page
|
2
|
page index (zero-based, new in v0.3.0) |
pageSize
|
10
|
page size (new in v0.3.0) |
pages
|
5
|
number of pages (new in v0.3.0) |
filters
|
[{ id: "Species", value: "petal" }]
|
array of column filter values (new in v0.3.0) |
searchValue
|
"petal"
|
table search value (new in v0.3.0) |
selected
|
[0, 1, 4]
|
array of selected row indices (zero-based, new in v0.3.0) |
pageRows
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
array of row data values in the page |
sortedData
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
sorted array of row data values in the table |
data
|
[{ Petal.Length: 1.7, Species: "setosa" }, ...]
|
original array of row data values in the table |