Written and maintained by CASRAI Editorial Board
Published
On this page
renderTable() is the Shiny server function that turns a small data frame or matrix into an HTML table, and tableOutput() is the matching user-interface placeholder. For large or interactive tables (paging, search, row selection) use the DT package’s DTOutput() and renderDT() instead. This guide shows the minimum working app, every formatting argument documented for renderTable(), how to choose between the table functions, and the mistakes that most often leave a table blank. It is for researchers who build Shiny apps in RStudio to display results from a data frame.
What renderTable() is used for in research
Research apps commonly show a summary table next to a plot: descriptive statistics, model coefficients, a sample of cleaned records. Shiny’s reference documentation describes renderTable() as a reactive table for small matrices and data frames, formatted through xtable::xtable(). The same page points to renderDataTable() for data frames that are too big to fit on a single page (Shiny reference, rendertable, read 2026-11-07).
Install or access
tableOutput() and renderTable() are part of the shiny package, which is distributed on CRAN. Install it from within R with install.packages("shiny") and load it with library(shiny). The DT package, needed only for interactive tables, installs the same way: install.packages("DT") (documentation: rstudio.github.io/DT/shiny.html, read 2026-11-07).
Step by step: show a data frame with tableOutput() and renderTable()
The Shiny reference example needs two matching pieces: a placeholder in the user interface, and an assignment to output$<id> in the server function.
- In the user interface, add
tableOutput('table'). The reference example places it insidefluidPage(fluidRow(column(12, tableOutput('table')))). - In the server function, assign
output$table <- renderTable(iris). The expression must return an object that xtable can format, such as a data frame or matrix. - Run the app with
shinyApp(ui, server). The built-inirisdata frame is displayed.
library(shiny)
ui <- fluidPage(
fluidRow(column(12, tableOutput('table')))
)
server <- function(input, output) {
output$table <- renderTable(iris)
}
shinyApp(ui, server)
Formatting arguments
The documented signature is renderTable(expr, striped = FALSE, hover = FALSE, bordered = FALSE, spacing = c("s", "xs", "m", "l"), width = "auto", align = NULL, rownames = FALSE, colnames = TRUE, digits = NULL, na = "NA", ..., env = parent.frame(), quoted = FALSE, outputArgs = list()) (Shiny reference, read 2026-11-07).
| Argument | What the reference says it does |
|---|---|
striped, hover, bordered |
Apply the Bootstrap table formats of the same name. All default to FALSE. |
spacing |
Cell spacing: "xs", "s" (default), "m" or "l". |
width |
Table width as a CSS unit; a plain number is given the unit px. Default "auto". |
align |
"l", "c" or "r" for all columns, or one character per column; "?" keeps the default for a column. With NULL, numeric columns are right-aligned and others left-aligned. |
rownames, colnames |
Whether to show row names (default FALSE) and column names (default TRUE). |
digits |
Number of decimal places for non-integer numeric columns. A negative value gives scientific notation. |
na |
Text shown for NA and NaN values. Default "NA". |
... |
Passed on to the xtable functions. |
Example: renderTable(iris, striped = TRUE, hover = TRUE, digits = 1, na = "missing").
renderTable() vs DT::renderDT() vs renderDataTable()
Choose by what the reader must do with the table. The functions below are the pairs documented by Shiny and DT; each output function must be paired with the render function from the same row.
| UI function | Server function | Documented purpose |
|---|---|---|
shiny::tableOutput() |
shiny::renderTable() |
Reactive table for small matrices and data frames, formatted with xtable. Static HTML. |
DT::DTOutput() |
DT::renderDT() |
Table built with the JavaScript DataTables library; DTOutput() is an alias of dataTableOutput() and renderDT() an alias of renderDataTable() in the DT package. Supports row, column and cell selection. |
shiny::dataTableOutput() |
shiny::renderDataTable() |
Marked deprecated in the Shiny reference: “use DT::renderDT() instead”. DT is described there as offering a superset of functionality, better performance and a better user experience. |
The DT documentation recommends the DT versions to avoid possible collisions with the Shiny functions of the same names (DT Shiny page, read 2026-11-07).
shiny datatable, shiny DT and r shiny datatable: the interactive route
Replace the two lines above with DT::DTOutput('table') in the user interface and output$table <- DT::renderDT(iris) in the server. In a Shiny app DT enables row selection by default and reports it to the server as inputs named after the output id (DT Shiny page, read 2026-11-07):
input$table_rows_selected: indices of selected rows.input$table_row_last_clicked: the most recently clicked row.input$table_columns_selected: selected columns, whentarget = 'column'is set.input$table_cells_selected: a two-column matrix of selected cells, whentarget = 'cell'is set.
If you need literal JavaScript inside DT options, the DT documentation says to use JS() rather than I().
Output and how to read it
renderTable() produces a plain table with no sorting, search or paging; every row of the data frame is written to the page, which is why the reference limits it to small tables. By default row names are hidden and numeric columns are right-aligned. DT adds paging, searching and sorting in the browser. Neither function changes the underlying data frame.
Troubleshooting
The table area is blank or the app reports an error
- Output ids do not match. The string in
tableOutput('table')must equal the name afteroutput$. Both reference examples use the same id on each side. - The expression does not return a table.
renderTable()needs an object usable with xtable, andrenderDataTable()needs a data frame or matrix. - Function pairs are mixed. Pair
tableOutput()withrenderTable(), andDTOutput()withrenderDT(), as in the comparison table above. Call DT functions with theDT::prefix so the Shiny function of the same name is not picked up. - Numbers show too many or too few decimals. Set
digitsinrenderTable(); a negative value switches to scientific notation.
Free alternatives
All options below are open-source R packages obtained from CRAN.
| Option | Use when | Source |
|---|---|---|
shiny renderTable() |
Small, static table with Bootstrap styling | Shiny reference |
DT renderDT() |
Larger or interactive table, with row/column/cell selection inputs | DT documentation |
FAQ
What is the difference between tableOutput and renderTable?
tableOutput() goes in the user interface and reserves the space; renderTable() goes in the server function and supplies the table. They are linked by the output id.
Is renderDataTable deprecated?
Yes. The Shiny reference states that renderDataTable() is deprecated and to use DT::renderDT() instead (read 2026-11-07).
Can I click a row in renderTable()?
The renderTable() reference documents no selection inputs. Row selection inputs such as input$table_rows_selected are documented for DT tables.
Sources
- Posit, Shiny reference: renderTable / tableOutput, read 2026-11-07.
- Posit, Shiny reference: renderDataTable / dataTableOutput, read 2026-11-07.
- DT package documentation: DT in Shiny, read 2026-11-07.
Related CASRAI guides: Plotly in R for interactive charts in the same app, and what R is used for.







