gtUtils 1.0.0 (July 25, 2026)
The first major update to gtUtils: 10 new themes and 27 new functions, along with new arguments, deprecations, and fixes across the existing functions.
New themes
Each takes an accent (or color) argument and a density argument.
-
gt_theme_broadsheet()sets a serif body with hairline rules and no fills.papertakes"white","salmon"for the financial-press pink, or a hex. -
gt_theme_midnight()is a dark theme on near-black. The default green-to-red ramp goes muddy there, so it ships withpal_midnightinstead. -
gt_theme_scoreboard()puts condensed uppercase labels on a solid band over tight rows.accentcolors the band. -
gt_theme_swiss()has no fills, no banding, and two rules in the whole table. -
gt_theme_terminal()is monospace, amber on black, with a rule under every row. -
gt_theme_brutalist()uses thick black rules and a large display face. -
gt_theme_drench()colors the entire table one saturated color and derives the type and rules from it. -
gt_theme_almanac()uses a slab body, condensed labels, and banded rows. -
gt_theme_booktabs()is an academic booktabs look: rules at the top and bottom, one under the labels, and no verticals. -
gt_theme_tufte()is a minimal-ink theme that strips the table back to its data.
New functions
Coloring:
-
gt_legend_continuous()draws a color legend for a continuously colored column, as a gradient, steps, or blocks. -
gt_legend_discrete()draws a discrete color key for a categorically colored column. -
gt_color_ranks()fills cells by value for columns that already hold ranks. -
gt_row_accent()puts a colored bar on the leading edge of each row. -
gt_percentile_bar()draws a percentile as a filled track with a numbered circular marker at the tip. -
gt_highlight_cells()fills individual cells that meet a condition. -
gt_highlight_na()styles and relabels missing values. -
gt_group_stripes()shades alternate row groups. -
gt_outliers()flags values outside an IQR fence, a number of standard deviations, or bounds you set.
Annotations:
-
gt_cutline()draws a labeled rule after a given row. -
gt_marginalia()styles a text column as margin notes, wrapping the text instead of letting it stretch the table. -
gt_title_header()builds a header with an optional kicker, subtitle, and date. -
gt_social_tag()puts social handles and Font Awesome icons in the source note. -
gt_spotlight()highlights rows by dimming the others. -
gt_watermark()puts a faint wordmark or logo behind the table body.
Formatting:
-
gt_delta()adds a computed change column between two value columns. -
gt_significance()adds significance stars from a p-value column and writes the matching legend. -
gt_scale_note()divides columns by 1,000 (or any divisor) and adds a “Figures in thousands.” note to match, e.g. -
gt_fmt_rank()formats numbers as ordinals. -
gt_fmt_tally()merges two or more count columns into one cell and can work out one of them as a share of the total.
Layout:
-
gt_snake()lays a long table out in side-by-side blocks, each with its own column labels. Body-cell styling applied before the snake is carried through the reshape. -
gt_snake_align()reshapes a parallel frame (a precomputed mask, per-cell colors) into the same blocks, for grids that live outside the table’s styles. -
gt_grid()arranges a list of separate tables in a grid, essentially facets for tables. -
gt_theme_preview()renders your data through every theme in the package.
Saving:
-
gt_social_crop()centers a saved table on a canvas of a given aspect ratio. -
gt_save_batch()writes one image per group.
Labels:
-
gt_wrap_labels()breaks long column labels across lines instead of letting them stretch the table.
Extended functions
-
gt_stack_tables()now takes a shared heading and footer (title,subtitle,caption,source_note,caption_rule) with matching*_stylelists, agapandalignfor the stack, and afilepath to write straight to a PNG. It follows the same styling convention asgt_grid(). -
gt_color_results()gains a tie state throughtie_color,tie_text_color, andtie_value, so a third result can be colored alongside wins and losses. -
gt_tiers()gainstier_columnto name the tier column andimage_columnsto choose which columns render as images, so a text column can sit beside the logos. It no longer requires a column literally namedtier. -
gt_set_font()gainsweightandstyleto set the weight and italic of the applied font.
Multiple columns and row targeting
gt_color_pills() took one column, despite the argument being named columns. Anything other than a single bare name or string failed with Can't convert to a symbol., including c(mpg, hp) and starts_with() (or any other tidyselect verb). It now takes tidyselect like the rest of the package. Several columns share one domain, so their colors stay comparable. Pill width is worked out per column, so each column’s pills line up with each other; and fill_type = "rank" ranks each column against itself.
rows is new on gt_color_pills(), gt_color_ranks(), and gt_percentile_bar(), taking an expression such as mpg > 20 or a vector of row indices, matching gt_spotlight() and gt_row_accent(). Rows left out keep their raw value.
gt_bold_rows() gains rows on the same convention. Its row and filter_statement arguments are deprecated. filter_statement took the expression as a string and ran it through parse(). Both still work, with one warning per session.
Legends pick up the scale
gt_color_ranks(), gt_color_pills(), and gt_percentile_bar() record the columns, palette, domain, reverse, and pal_type they used. gt_legend_continuous() reads whatever the caller did not supply, so this now works:
gt(df) %>%
gt_color_ranks(net, palette = "viridis::mako", domain = c(-10, 12)) %>%
gt_legend_continuous()Previously, the palette and domain had to be repeated in full, and changing one without the other produced a legend that disagreed with the cells it explained, with nothing to flag it.
gt_tiers() records its level = color mapping the same way, so gt_legend_discrete() can be called with no key_info.
Anything passed explicitly wins over the recorded value, and with several coloring calls the most recent is the one recorded. The record is an attribute on the table, so it survives a pipeline apart from gt_snake(), which rebuilds the table from its data.
Selection consistency
-
gt_color_results()tookresult_columnas a string only; a bare column name errored. It now accepts either. -
gt_indicator_boxes()gainscolumns, naming the columns to convert, which is how every other function in the package reads.key_columnsnamed the columns to leave alone, the inverted form, and accepted only a character vector. It is kept, now also takestidyselect, and passing both is an error. -
gt_tiers()acceptslevelsas a single named vector oflevel = color, the same shapegt_legend_discrete()takes, so one object can drive the tiers and their key.
New arguments
-
gt_color_pills()gainstext_colorto override the automatic contrast color andna_colorto fill the pill drawn over a missing value. -
gt_indicator_boxes()gainstext_sizeandtext_weightfor the box text. -
gt_538_caption()gainsrule_color,rule_width,size, andalign. -
gt_column_subheaders()gainsheading_size,subtitle_size, andfont.
Deprecations
-
gt_centered_legend()is deprecated in favor ofgt_legend_discrete(). The old name still work with a deprecation warning. - The first argument of
gt_set_font()andgt_column_subheaders()is nowgt_object, matching the rest of the package. The oldgt_tableargument still works with a deprecation warning.
Bug fixes
-
gt_column_subheaders()used%||%without importing it, so it failed with “could not find function” for everyone. Now imported fromrlang. -
gt_border_bars_top()andgt_border_bars_bottom()calledfilter()unqualified, which could resolve tostats::filter()depending on what the user had attached. Now imported explicitly fromdplyr. -
gt_border_bars_*()reachedgoogle_font()throughgt:::when the function is exported, and errored outright on a theme that set no font on the title or source notes. Both now fall back to the inherited font. -
gt_bold_rows():highlight_color = NULLnow leaves the fill off, matching its documentation. It previously forced a white fill. -
gt_tiers():styleis now passed through togt_theme_tier(), so"light"works. It was fixed at"dark"regardless. The theme, images, and labels are applied once rather than once per tier, and each tier now takes its own contrast text color. -
gt_color_pills()andgt_indicator_boxes():digits = NULLno longer prints trailing zeros, so a whole number reads as21rather than21.0000. -
gt_538_caption()no longer errors when the rendered table carries no color to borrow for the rule; it falls back to a neutral gray.top_captionnow defaults toNULL, so a bottom caption can be set on its own.
