Publication-Ready Tables with gt
Introduction
The gt package (short for “grammar of tables”) is an R package that transforms data frames into presentation-ready tables. Developed by the RStudio team, gt provides a consistent API for creating tables that look professional without needing HTML, CSS, or LaTeX expertise.
Why use gt? If you’ve ever struggled with formatting tables in R for reports, papers, or dashboards, gt solves that problem. It works with tibbles, data frames, and even Spreadsheet cells objects. The output renders as HTML by default, but you can export to PNG, PDF, LaTeX, and RTF.
Install gt from CRAN:
install.packages("gt")
You’ll also want the tidyverse for data manipulation:
install.packages("tidyverse")
Load both packages:
library(gt)
library(tidyverse)
Basic Table Creation
Creating a basic gt table is straightforward. Pass any data frame to gt() and it renders immediately:
# Sample data
sales_data <- tibble(
product = c("Widget A", "Widget B", "Widget C", "Widget D"),
quarter = c("Q1", "Q1", "Q1", "Q1"),
units_sold = c(150, 230, 180, 95),
revenue = c(4500, 6900, 5400, 2850)
# Create the table
gt_table <- gt(sales_data)
gt_table
The output displays a clean table with column names as headers. You can customize column labels using cols_label():
gt(sales_data) %>%
cols_label(
product = "Product",
quarter = "Quarter",
units_sold = "Units Sold",
revenue = "Revenue ($)"
)
Add a title and subtitle for context:
gt(sales_data) %>%
tab_header(
title = "Q1 Sales Report",
subtitle = "Product performance by unit volume and revenue"
)
Formatting Columns
gt provides specialized functions for formatting different data types. These functions modify display without changing the underlying data.
Currency Formatting
Format values as currency with fmt_currency():
gt(sales_data) %>%
fmt_currency(columns = revenue, currency = "USD")
Use accounting = TRUE for negative values in parentheses:
financial_data <- tibble(
category = c("Revenue", "Expenses", "Net Income"),
amount = c(150000, -95000, 55000)
gt(financial_data) %>%
fmt_currency(amount, currency = "USD", accounting = TRUE)
Percentage Formatting
Use fmt_percent() for percentage values:
growth_data <- tibble(
metric = c("User Growth", "Retention", "Conversion"),
value = c(0.245, 0.78, 0.032)
gt(growth_data) %>%
fmt_percent(value, decimals = 1)
Date and Time Formatting
Format dates with fmt_date():
event_data <- tibble(
event = c("Conference", "Workshop", "Meetup"),
date = as.Date(c("2024-03-15", "2024-04-22", "2024-05-10"))
gt(event_data) %>%
fmt_date(date, date_style = "wd_m_day_year")
Number Formatting
Control decimal places and significant figures:
gt(sales_data) %>%
fmt_number(units_sold, decimals = 0) %>%
fmt_number(revenue, decimals = 2, sep = ",")
Styling
Themes
gt includes built-in themes via opt_table_theme():
gt(sales_data) %>%
opt_table_theme(theme = "spa")
Other available themes include “default”, “slate”, “dark”, and “honda”.
Cell Colors
Apply background colors to cells using data_color():
gt(sales_data) %>%
data_color(
columns = revenue,
colors = scales::col_numeric(
palette = c("white", "green"),
domain = c(0, max(sales_data$revenue))
)
)
Borders and Alignment
Control border styling with tab_style():
gt(sales_data) %>%
tab_style(
style = cell_text(weight = "bold"),
locations = cells_column_labels()
) %>%
tab_style(
style = cell_borders(sides = "bottom", color = "black", weight = px(2)),
locations = cells_column_labels()
)
Align text with opt_align_table_header() and cols_align():
gt(sales_data) %>%
opt_align_table_header(align = "center") %>%
cols_align(align = "center", columns = quarter)
Advanced Features
Row Groups
Group rows by a column using row_group_order():
regional_sales <- tibble(
region = c("North", "North", "South", "South", "East", "East"),
product = c("Widget A", "Widget B", "Widget A", "Widget B", "Widget A", "Widget B"),
sales = c(500, 750, 620, 480, 890, 670)
gt(regional_sales) %>%
row_group_order(groups = c("North", "South", "East"))
Column Spanning
Create spanning headers with tab_spanner():
combined_data <- tibble(
product = c("Widget A", "Widget B"),
q1_sales = c(150, 230),
q2_sales = c(180, 265),
q1_units = c(4500, 6900),
q2_units = c(5400, 7950)
gt(combined_data) %>%
tab_spanner(label = "Q1", columns = c(q1_sales, q1_units)) %>%
tab_spanner(label = "Q2", columns = c(q2_sales, q2_units))
Footnotes
Add footnotes with tab_footnote():
gt(sales_data) %>%
tab_footnote(
footnote = "Data includes returns",
locations = cells_column_labels(columns = units_sold)
)
Export Options
HTML
Save HTML output directly:
gt_table <- gt(sales_data)
gtsave(gt_table, "sales_table.html")
PNG
Export as PNG for presentations:
gtsave(gt_table, "sales_table.png")
LaTeX
For academic papers, export to LaTeX:
gtsave(gt_table, "sales_table.tex")
Generate PDF output:
gtsave(gt_table, "sales_table.pdf")
See Also
- Data Visualization with ggplot2 — for creating charts and graphs to accompany your tables
- Data Manipulation with dplyr — for preparing data before feeding it into gt
- Interactive Tables with reactable — for sortable, filterable tables in Shiny apps