Publication-Ready Tables with gt

· 4 min read · Updated March 12, 2026 · beginner
r gt tables data-viz tidyverse

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")

PDF

Generate PDF output:

gtsave(gt_table, "sales_table.pdf")

See Also