Skip to main content
v2026.11,986 entries · CC-BY 4.0

renderTable in Shiny: tableOutput(), DT and renderDataTable Compared

renderTable and tableOutput in Shiny: working code, every formatting argument, and when to use DT::renderDT instead of deprecated renderDataTable.

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.

  1. In the user interface, add tableOutput('table'). The reference example places it inside fluidPage(fluidRow(column(12, tableOutput('table')))).
  2. 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.
  3. Run the app with shinyApp(ui, server). The built-in iris data 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, when target = 'column' is set.
  • input$table_cells_selected: a two-column matrix of selected cells, when target = '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 after output$. Both reference examples use the same id on each side.
  • The expression does not return a table. renderTable() needs an object usable with xtable, and renderDataTable() needs a data frame or matrix.
  • Function pairs are mixed. Pair tableOutput() with renderTable(), and DTOutput() with renderDT(), as in the comparison table above. Call DT functions with the DT:: prefix so the Shiny function of the same name is not picked up.
  • Numbers show too many or too few decimals. Set digits in renderTable(); 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

Related CASRAI guides: Plotly in R for interactive charts in the same app, and what R is used for.

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about renderTable in Shiny: tableOutput(), DT and renderDataTable Compared

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →