Summary tables using 2-sided formulae: crosstabs, frequencies, table 1s and more.


datasummary can use any summary function which produces one numeric or character value per variable. The examples section of this documentation shows how to define custom summary functions.

modelsummary also supplies several shortcut summary functions which can be used in datasummary() formulas: Min, Max, Mean, Median, Var, SD, NPercent, NUnique, Ncol, P0, P25, P50, P75, P100.

See the Details and Examples sections below, and the vignettes on the modelsummary website:




  output = "default",
  fmt = 2,
  title = NULL,
  notes = NULL,
  align = NULL,
  add_columns = NULL,
  add_rows = NULL,
  sparse_header = TRUE,
  escape = TRUE,


formula A two-sided formula to describe the table: rows ~ columns. See the Examples section for a mini-tutorial and the Details section for more resources. Grouping/nesting variables can appear on both sides of the formula, but all summary functions must be on one side.
data A data.frame (or tibble)

filename or object type (character string)

  • Supported filename extensions: .docx, .html, .tex, .md, .txt, .csv, .xlsx, .png, .jpg

  • Supported object types: "default", "html", "markdown", "latex", "latex_tabular", "typst", "data.frame", "tinytable", "gt", "kableExtra", "huxtable", "flextable", "DT", "jupyter". The "modelsummary_list" value produces a lightweight object which can be saved and fed back to the modelsummary function.

  • The "default" output format can be set to "tinytable", "kableExtra", "gt", "flextable", "huxtable", "DT", or "markdown"

    • If the user does not choose a default value, the packages listed above are tried in sequence.

    • Session-specific configuration: options(“modelsummary_factory_default” = “gt”)

    • Persistent configuration: config_modelsummary(output = “markdown”)

  • Warning: Users should not supply a file name to the output argument if they intend to customize the table with external packages. See the ‘Details’ section.

  • LaTeX compilation requires the booktabs and siunitx packages, but siunitx can be disabled or replaced with global options. See the ‘Details’ section.


how to format numeric values: integer, user-supplied function, or modelsummary function.

  • Integer: Number of decimal digits

  • User-supplied functions:

    • Any function which accepts a numeric vector and returns a character vector of the same length.

  • modelsummary functions:

    • fmt = fmt_significant(2): Two significant digits (at the term-level)

    • fmt = fmt_sprintf(“%.3f”): See ?sprintf

    • fmt = fmt_identity(): unformatted raw values

title string
notes list or vector of notes to append to the bottom of the table.

A string with a number of characters equal to the number of columns in the table (e.g., align = “lcc”). Valid characters: l, c, r, d.

  • "l": left-aligned column

  • "c": centered column

  • "r": right-aligned column

  • "d": dot-aligned column. For LaTeX/PDF output, this option requires at least version 3.0.25 of the siunitx LaTeX package. See the LaTeX preamble help section below for commands to insert in your LaTeX preamble.

add_columns a data.frame (or tibble) with the same number of rows as your main table.
add_rows a data.frame (or tibble) with the same number of columns as your main table. By default, rows are appended to the bottom of the table. You can define a "position" attribute of integers to set the row positions. See Examples section below.
sparse_header TRUE or FALSE. TRUE eliminates column headers which have a unique label across all columns, except for the row immediately above the data. FALSE keeps all headers. The order in which terms are entered in the formula determines the order in which headers appear. For example, x~mean*z will print the mean-related header above the z-related header.’
escape boolean TRUE escapes or substitutes LaTeX/HTML characters which could prevent the file from compiling/displaying. TRUE escapes all cells, captions, and notes. Users can have more fine-grained control by setting escape=FALSE and using an external command such as: modelsummary(model, “latex”) |> tinytable::format_tt(tab, j=1:5, escape=TRUE)
all other arguments are passed through to the table-making functions tinytable::tt, kableExtra::kbl, gt::gt, DT::datatable, etc. depending on the output argument. This allows users to pass arguments directly to datasummary in order to affect the behavior of other functions behind the scenes.


Visit the ‘modelsummary’ website for more usage examples:

The ‘datasummary’ function is a thin wrapper around the ‘tabular’ function from the ‘tables’ package. More details about table-making formulas can be found in the ‘tables’ package documentation: ?tables::tabular

Hierarchical or "nested" column labels are only available for these output formats: tinytable, kableExtra, gt, html, rtf, and LaTeX. When saving tables to other formats, nested labels will be combined to a "flat" header.

Global Options

The behavior of modelsummary can be modified by setting global options. For example:

  • options(modelsummary_model_labels = “roman”)

The rest of this section describes each of the options above.

Model labels: default column names

These global option changes the style of the default column headers:

  • options(modelsummary_model_labels = “roman”)

  • options(modelsummary_panel_labels = “roman”)

The supported styles are: "model", "panel", "arabic", "letters", "roman", "(arabic)", "(letters)", "(roman)"

The panel-specific option is only used when shape=“rbind”

Table-making packages

modelsummary supports 6 table-making packages: tinytable, kableExtra, gt, flextable, huxtable, and DT. Some of these packages have overlapping functionalities. To change the default backend used for a specific file format, you can use ’ the options function:

options(modelsummary_factory_html = ‘kableExtra’) options(modelsummary_factory_word = ‘huxtable’) options(modelsummary_factory_png = ‘gt’) options(modelsummary_factory_latex = ‘gt’) options(modelsummary_factory_latex_tabular = ‘kableExtra’)

Table themes

Change the look of tables in an automated and replicable way, using the modelsummary theming functionality. See the vignette:

  • modelsummary_theme_gt

  • modelsummary_theme_kableExtra

  • modelsummary_theme_huxtable

  • modelsummary_theme_flextable

  • modelsummary_theme_dataframe

Model extraction functions

modelsummary can use two sets of packages to extract information from statistical models: the easystats family (performance and parameters) and broom. By default, it uses easystats first and then falls back on broom in case of failure. You can change the order of priorities or include goodness-of-fit extracted by both packages by setting:

options(modelsummary_get = “easystats”)

options(modelsummary_get = “broom”)

options(modelsummary_get = “all”)

Formatting numeric entries

By default, LaTeX tables enclose all numeric entries in the command from the siunitx package. To prevent this behavior, or to enclose numbers in dollar signs (for LaTeX math mode), users can call:

options(modelsummary_format_numeric_latex = “plain”)

options(modelsummary_format_numeric_latex = “mathmode”)

A similar option can be used to display numerical entries using MathJax in HTML tables:

options(modelsummary_format_numeric_html = “mathjax”)

LaTeX preamble

When creating LaTeX via the tinytable backend (default in version 2.0.0 and later), it is useful to include the following commands in the LaTeX preamble of your documents. Note that they are added automatically when compiling Rmarkdown or Quarto documents.





# The left-hand side of the formula describes rows, and the right-hand side
# describes columns. This table uses the "mpg" variable as a row and the "mean"
# function as a column:

datasummary(mpg ~ mean, data = mtcars)
mpg 20.09
# This table uses the "mean" function as a row and the "mpg" variable as a column:

datasummary(mean ~ mpg, data = mtcars)
mean 20.09
# Display several variables or functions of the data using the "+"
# concatenation operator. This table has 2 rows and 2 columns:

datasummary(hp + mpg ~ mean + sd, data = mtcars)
mean sd
hp 146.69 68.56
mpg 20.09 6.03
# Nest variables or statistics inside a "factor" variable using the "*" nesting
# operator. This table shows the mean of "hp" and "mpg" for each value of
# "cyl":

mtcars$cyl <- as.factor(mtcars$cyl)
datasummary(hp + mpg ~ cyl * mean, data = mtcars)
4 6 8
hp 82.64 122.29 209.21
mpg 26.66 19.74 15.10
# If you don't want to convert your original data
# to factors, you can use the 'Factor()'
# function inside 'datasummary' to obtain an identical result:

datasummary(hp + mpg ~ Factor(cyl) * mean, data = mtcars)
4 6 8
hp 82.64 122.29 209.21
mpg 26.66 19.74 15.10
# You can nest several variables or statistics inside a factor by using
# parentheses. This table shows the mean and the standard deviation for each
# subset of "cyl":

datasummary(hp + mpg ~ cyl * (mean + sd), data = mtcars)
4 6 8
mean sd mean sd mean sd
hp 82.64 20.93 122.29 24.26 209.21 50.98
mpg 26.66 4.51 19.74 1.45 15.10 2.56
# Summarize all numeric variables with 'All()'
datasummary(All(mtcars) ~ mean + sd, data = mtcars)
mean sd
mpg 20.09 6.03
disp 230.72 123.94
hp 146.69 68.56
drat 3.60 0.53
wt 3.22 0.98
qsec 17.85 1.79
vs 0.44 0.50
am 0.41 0.50
gear 3.69 0.74
carb 2.81 1.62
# Define custom summary statistics. Your custom function should accept a vector
# of numeric values and return a single numeric or string value:

minmax <- function(x) sprintf("[%.2f, %.2f]", min(x), max(x))
mean_na <- function(x) mean(x, na.rm = TRUE)

datasummary(hp + mpg ~ minmax + mean_na, data = mtcars)
minmax mean_na
hp [52.00, 335.00] 146.69
mpg [10.40, 33.90] 20.09
# To handle missing values, you can pass arguments to your functions using
# '*Arguments()'

datasummary(hp + mpg ~ mean * Arguments(na.rm = TRUE), data = mtcars)
hp 146.69
mpg 20.09
# For convenience, 'modelsummary' supplies several convenience functions
# with the argument `na.rm=TRUE` by default: Mean, Median, Min, Max, SD, Var,
# P0, P25, P50, P75, P100, NUnique, Histogram

#datasummary(hp + mpg ~ Mean + SD + Histogram, data = mtcars)

# These functions also accept a 'fmt' argument which allows you to
# round/format the results

datasummary(hp + mpg ~ Mean * Arguments(fmt = "%.3f") + SD * Arguments(fmt = "%.1f"), data = mtcars)
Mean SD
hp 146.688 68.6
mpg 20.091 6.0
# Save your tables to a variety of output formats:
f <- hp + mpg ~ Mean + SD
#datasummary(f, data = mtcars, output = 'table.html')
#datasummary(f, data = mtcars, output = 'table.tex')
#datasummary(f, data = mtcars, output = '')
#datasummary(f, data = mtcars, output = 'table.docx')
#datasummary(f, data = mtcars, output = 'table.pptx')
#datasummary(f, data = mtcars, output = 'table.jpg')
#datasummary(f, data = mtcars, output = 'table.png')

# Display human-readable code
#datasummary(f, data = mtcars, output = 'html')
#datasummary(f, data = mtcars, output = 'markdown')
#datasummary(f, data = mtcars, output = 'latex')

# Return a table object to customize using a table-making package
#datasummary(f, data = mtcars, output = 'tinytable')
#datasummary(f, data = mtcars, output = 'gt')
#datasummary(f, data = mtcars, output = 'kableExtra')
#datasummary(f, data = mtcars, output = 'flextable')
#datasummary(f, data = mtcars, output = 'huxtable')

# add_rows
new_rows <- data.frame(a = 1:2, b = 2:3, c = 4:5)
attr(new_rows, 'position') <- c(1, 3)
datasummary(mpg + hp ~ mean + sd, data = mtcars, add_rows = new_rows)
mean sd
1.00 2.00 4.00
mpg 20.09 6.03
2.00 3.00 5.00
hp 146.69 68.56