| Title: | Lightweight Tables via JSON Specs and JavaScript |
|---|---|
| Description: | A lightweight grammar of tables. Build a table by declaring a JSON spec (titles, spanners, row groups, footnotes, formatting functions, etc.); a tiny vanilla JavaScript runtime builds the HTML table from the spec on page load. Cells can hold inline plots (error bars, dot plots, mini line and bar charts) drawn as SVG in the browser from the numbers alone. Tables can optionally be made interactive (sorting, searching, filtering, pagination, column hiding, expandable row detail, and CSV download) via a separate extension loaded only when requested. No 'sass', no 'V8', no 'htmlwidgets' — just base R and 'xfun' ('htmltools' is used only for the optional Shiny binding and for embedding tables in other HTML output). |
| Authors: | Yihui Xie [aut, cre, cph] (ORCID: <https://orcid.org/0000-0003-0645-5666>, URL: https://yihui.org) |
| Maintainer: | Yihui Xie <[email protected]> |
| License: | MIT + file LICENSE |
| Version: | 0.5.1 |
| Built: | 2026-10-19 20:59:41 UTC |
| Source: | https://github.com/yihui/lt |
lt_tbl to HTMLEmits the CSS+JS runtime and a script block carrying the table's JSON spec. Multiple tables on the same page only need the runtime once.
## S3 method for class 'lt_tbl' format(x, fragment = TRUE, inline_assets = TRUE, assets = TRUE, ...)## S3 method for class 'lt_tbl' format(x, fragment = TRUE, inline_assets = TRUE, assets = TRUE, ...)
x |
An |
fragment |
If |
inline_assets |
If |
assets |
Which runtime assets to include: |
... |
Reserved for future use. |
A character scalar containing HTML.
tbl = lt(head(mtcars)) html = format(tbl) format(tbl, fragment = FALSE, inline_assets = FALSE)tbl = lt(head(mtcars)) html = format(tbl) format(tbl, fragment = FALSE, inline_assets = FALSE)
Entry point of the lightweight grammar of tables. Returns an object (a
list) that records the data plus a list of table-modifying operations. The
object is rendered to HTML by format() (called automatically by the
print method).
lt(data, ...) ## Default S3 method: lt(data, auto_format = TRUE, auto_label = TRUE, ...)lt(data, ...) ## Default S3 method: lt(data, auto_format = TRUE, auto_label = TRUE, ...)
data |
A data frame (or anything coercible to one). |
... |
Arguments passed to methods. |
auto_format |
Whether to automatically format numeric columns (rounding,
thousand separators, percentage detection). Set to |
auto_label |
Whether to automatically clean column names for display
by replacing separators ( |
A table object that can be piped into lt_*() functions.
By default all cell values and text (titles, labels, footnotes, ...) are
HTML-escaped, so special characters like <, >, and & render as
literal text. To emit content as raw HTML instead:
For body cells, mark whole columns with lt_html().
For a title, subtitle, column label, spanner, footnote, or note, wrap the
text in I(). For example, lt_header(x, I("<b>Report</b>")) renders the
title as raw HTML, while lt_header(x, "<b>Report</b>") shows the literal
<b> tags.
When a cell value has been formatted (e.g., by auto-formatting or
lt_format()), the original value is stored in the cell's title
attribute and shown as a tooltip on hover. Additionally:
Alt + Click on a table toggles display of all raw values in that table.
Alt + Double-Click on a table toggles raw values globally (all tables
on the page).
Raw values are shown as (value) after the formatted text, highlighted
with a light yellow background.
By default, missing (NA) cells display an em dash (—) so they are not
confused with empty strings. Change the table-wide default with the
lt.missing global option, e.g. options(lt.missing = "n/a"); set it to
the empty string (options(lt.missing = "")) to leave NA cells blank.
Use lt_sub() with missing = to override the text for specific columns.
lt(head(mtcars[, 1:4]))lt(head(mtcars[, 1:4]))
Override the auto-detected alignment for specific columns. By default, numeric columns are right-aligned and character columns are left-aligned.
lt_align(x, columns, align = c("left", "center", "right"))lt_align(x, columns, align = c("left", "center", "right"))
x |
An |
columns |
Columns to select: a character vector of column names,
integer positions, or a one-sided formula. A formula whose right-hand side
references the pronoun |
align |
One of |
x with the alignment recorded.
lt(head(mtcars)) |> lt_align(~ cyl + gear, "center")lt(head(mtcars)) |> lt_align(~ cyl + gear, "center")
Add user-supplied stylesheets or inline rules that render after the built-in CSS, so rules can override the defaults.
lt_css(x, ...)lt_css(x, ...)
x |
An |
... |
Unnamed arguments are stylesheet paths or URLs. A bare
filename (no directory component) that does not exist in the working
directory is resolved against the stylesheets shipped with lt, so
e.g. Named arguments define inline CSS rules scoped to |
x with the stylesheets recorded.
tbl = lt(head(mtcars)) tbl |> lt_style("mpg", test = "v => v > 20", class = "high") |> lt_css(.high = list(background = "#cfc", fontWeight = "bold"))tbl = lt(head(mtcars)) tbl |> lt_style("mpg", test = "v => v > 20", class = "high") |> lt_css(.high = list(background = "#cfc", fontWeight = "bold"))
Format date or datetime columns using JavaScript's native Date methods.
The underlying data should be Date or POSIXt in R (serialized as
new Date(...) for the browser).
lt_date(x, columns, method = NULL, locale = NULL, options = NULL)lt_date(x, columns, method = NULL, locale = NULL, options = NULL)
x |
An |
columns |
Columns to select: a character vector of column names,
integer positions, or a one-sided formula. A formula whose right-hand side
references the pronoun |
method |
A JS Date method name to call (e.g., |
locale |
A BCP 47 locale string (e.g., |
options |
A named list of
|
x with the date formatting recorded.
The formatted date may differ from the input date depending on the
viewer's local timezone. JavaScript's new Date("2024-01-15") parses
date-only strings as UTC midnight, but toLocaleDateString() converts to
the local timezone. For example, 2024-01-15 will display as
2024-01-14 for a viewer at GMT-6. To avoid this, pass
options = list(timeZone = "UTC").
d = data.frame( event = c("Launch", "Update"), date = as.Date(c("2024-01-15", "2024-06-30")) ) lt(d) |> lt_date(~ date) lt(d) |> lt_date(~ date, options = list(year = "numeric", month = "short"))d = data.frame( event = c("Launch", "Update"), date = as.Date(c("2024-01-15", "2024-06-30")) ) lt(d) |> lt_date(~ date) lt(d) |> lt_date(~ date, options = list(year = "numeric", month = "short"))
The htmltools::htmlDependency() bundling lt's runtime assets, for embedding
lt tables in other HTML output (e.g. another htmlwidget or a reactable
cell) and rendering them client-side with LT.render() / LT.buildHtml()
on a spec from lt_spec(). Requires the htmltools package.
lt_dependency(interactive = FALSE, plot = FALSE, shiny = FALSE)lt_dependency(interactive = FALSE, plot = FALSE, shiny = FALSE)
interactive |
Whether to also include the interactivity extension (the
assets behind |
plot |
Whether to also include the graphics module (the assets behind
|
shiny |
Whether to include the Shiny output binding (only needed by
|
An html_dependency object.
if (requireNamespace('htmltools', quietly = TRUE)) lt_dependency(interactive = TRUE)if (requireNamespace('htmltools', quietly = TRUE)) lt_dependency(interactive = TRUE)
Render each row's values across one or more columns as inline dots on a
shared horizontal scale: N columns give N dots per row, laid out by value. It
is lightweight like lt_errorbar() and lt_sparkline() – only the numbers
travel to the client and the SVG is drawn in the browser, so an interactive
table (lt_interactive()) draws only the rows on the current page.
lt_dotplot( x, columns, limits = NULL, color = FALSE, labels = NULL, stagger = FALSE, into = NULL, width = 160, height = NULL, hide = TRUE, axis = TRUE )lt_dotplot( x, columns, limits = NULL, color = FALSE, labels = NULL, stagger = FALSE, into = NULL, width = 160, height = NULL, hide = TRUE, axis = TRUE )
x |
An |
columns |
The value column(s): one dot is drawn per column, read left to
right across the row, all on a scale shared across the columns. The plot is
drawn in the first column's cells, or into |
limits |
Numeric |
color |
Series colors. |
labels |
Legend labels, one per series, used when colored. Defaults to the series' value-column names. |
stagger |
If |
into |
Optional name of a dedicated column to draw the plot into,
instead of the first series' value column. The series columns ( |
width, height
|
Pixel size of each cell's SVG. |
hide |
If |
axis |
Draw a shared horizontal axis (a baseline with tick marks and
labels at "nice" round values) in the table footer under the plot column,
plus faint vertical gridlines inside each cell at the same tick positions
to help read the bars. |
Since the cell shows every named column, the column header defaults to all
their names joined by " / " (e.g. "Before / After"); override it with a
later lt_label() on that column.
x with the dot-plot column recorded.
d = data.frame( group = c("A", "B", "C"), before = c(3, 5, 4), after = c(6, 7, 5) ) # one dot per column, colored and keyed by a footer legend, with an axis lt(d) |> lt_dotplot(~ before + after, color = TRUE) # custom colors and labels lt(d) |> lt_dotplot( ~ before + after, color = c("#999", "#1a9641"), labels = c("Baseline", "Follow-up") ) # draw into a dedicated column, keeping the value columns visible as text lt(d) |> lt_dotplot(~ before + after, into = "plot", hide = FALSE)d = data.frame( group = c("A", "B", "C"), before = c(3, 5, 4), after = c(6, 7, 5) ) # one dot per column, colored and keyed by a footer legend, with an axis lt(d) |> lt_dotplot(~ before + after, color = TRUE) # custom colors and labels lt(d) |> lt_dotplot( ~ before + after, color = c("#999", "#1a9641"), labels = c("Baseline", "Follow-up") ) # draw into a dedicated column, keeping the value columns visible as text lt(d) |> lt_dotplot(~ before + after, into = "plot", hide = FALSE)
Render a numeric column's cells as a small inline SVG: a point at the
estimate and a horizontal bar (with end caps) from the lower to the upper
bound, drawn on a scale shared across the column so rows are comparable at a
glance (handy for
a forest plot of effect sizes with confidence intervals). It is lightweight:
only the numbers travel to the client, and the SVG is drawn in the browser —
so for an interactive table (lt_interactive()) only the rows on the current
page are drawn.
lt_errorbar( x, ..., limits = NULL, ref = NULL, into = NULL, width = 160, height = NULL, hide = TRUE, axis = FALSE, color = FALSE, labels = NULL )lt_errorbar( x, ..., limits = NULL, ref = NULL, into = NULL, width = 160, height = NULL, hide = TRUE, axis = FALSE, color = FALSE, labels = NULL )
x |
An |
... |
One or more error-bar series, each naming the point estimate, the
lower bound, and the upper bound, in that order: either a two-sided formula
|
limits |
Numeric |
ref |
Optional value at which to draw a vertical reference line (e.g.
|
into |
Optional name of a dedicated column to draw the plot into,
instead of the first series' value column. The series columns ( |
width, height
|
Pixel size of each cell's SVG. |
hide |
If |
axis |
Draw a shared horizontal axis (a baseline with tick marks and
labels at "nice" round values) in the table footer under the plot column,
plus faint vertical gridlines inside each cell at the same tick positions
to help read the bars. |
color |
Series colors. |
labels |
Legend labels, one per series, used when colored. Defaults to the series' value-column names. |
Several series can share one cell: pass one triple per series and each row
shows one point-and-bar per series, stacked vertically on the same shared
scale (e.g. a risk difference for each of several treatment arms). Color the
series and a legend is drawn in the footer, as for lt_dotplot().
x with the error-bar column recorded.
d = data.frame( term = c("A", "B", "C"), est = c(0.2, -0.1, 0.4), lo = c(0.0, -0.3, 0.1), hi = c(0.4, 0.1, 0.7) ) # a two-sided formula names the estimate (LHS) and the bounds (RHS) lt(d) |> lt_errorbar(est ~ lo + hi, ref = 0) # keep the bounds columns visible and add a labeled axis lt(d) |> lt_errorbar(est ~ lo + hi, hide = FALSE, axis = "Effect") # draw into a dedicated column, keeping every value column visible as text lt(d) |> lt_errorbar(est ~ lo + hi, into = "forest", hide = FALSE) # auto-fit the plot to its column (grows/shrinks as the column is resized) lt(d) |> lt_errorbar(est ~ lo + hi, into = "forest", width = "100%") # several series stacked in each cell, colored with a footer legend d2 = data.frame( term = c("A", "B"), e1 = c(0.2, 0.4), l1 = c(0, 0.2), u1 = c(0.4, 0.6), e2 = c(-0.1, 0.1), l2 = c(-0.3, -0.1), u2 = c(0.1, 0.3) ) lt(d2) |> lt_errorbar( e1 ~ l1 + u1, e2 ~ l2 + u2, ref = 0, color = TRUE, labels = c("Drug A", "Drug B") )d = data.frame( term = c("A", "B", "C"), est = c(0.2, -0.1, 0.4), lo = c(0.0, -0.3, 0.1), hi = c(0.4, 0.1, 0.7) ) # a two-sided formula names the estimate (LHS) and the bounds (RHS) lt(d) |> lt_errorbar(est ~ lo + hi, ref = 0) # keep the bounds columns visible and add a labeled axis lt(d) |> lt_errorbar(est ~ lo + hi, hide = FALSE, axis = "Effect") # draw into a dedicated column, keeping every value column visible as text lt(d) |> lt_errorbar(est ~ lo + hi, into = "forest", hide = FALSE) # auto-fit the plot to its column (grows/shrinks as the column is resized) lt(d) |> lt_errorbar(est ~ lo + hi, into = "forest", width = "100%") # several series stacked in each cell, colored with a footer legend d2 = data.frame( term = c("A", "B"), e1 = c(0.2, 0.4), l1 = c(0, 0.2), u1 = c(0.4, 0.6), e2 = c(-0.1, 0.1), l2 = c(-0.3, -0.1), u2 = c(0.1, 0.3) ) lt(d2) |> lt_errorbar( e1 ~ l1 + u1, e2 ~ l2 + u2, ref = 0, color = TRUE, labels = c("Drug A", "Drug B") )
Save a table to disk. The output format is chosen from the file extension
of output: .html writes an HTML table, .pdf writes a vector PDF, and
any other extension writes a PNG. PDF and PNG are produced by rendering the
table in a headless Chromium browser (via xfun::browser_print()).
lt_export( x, output = "lt.html", method = c("auto", "node", "browser", "raw"), css = TRUE, fragment = FALSE, tidy = FALSE, crop = TRUE, width = NULL, padding = 8, browser = NULL, ... )lt_export( x, output = "lt.html", method = c("auto", "node", "browser", "raw"), css = TRUE, fragment = FALSE, tidy = FALSE, crop = TRUE, width = NULL, padding = 8, browser = NULL, ... )
x |
An |
output |
Output file path. Its extension selects the format: |
method |
How to produce the HTML |
css |
Whether to include the lt.css runtime stylesheet in the HTML
output. User CSS from |
fragment |
If |
tidy |
Whether to pretty-print the baked |
crop |
Whether to crop the PDF/PNG tightly to the table, removing the
surrounding page whitespace. This adds a preliminary browser pass to
measure the rendered table. Set to |
width |
The width of the table in CSS pixels. By default ( |
padding |
Padding in CSS pixels to keep around the table when
cropping. A single value (all sides) or a length-two vector
|
browser |
Path to the Chromium-based browser; passed to
|
... |
Passed to |
For .html output, method controls how the <table> is produced:
"raw" writes the JavaScript-spec HTML, so the table is built in the
browser by the lt.js runtime when the file is viewed; the other methods
bake a static <table> up front by running lt.js once (via "node" in
Node.js or "browser" in a headless Chromium browser; "auto" picks Node
if available, else the browser), so the saved file needs no JavaScript to
view. method, css, fragment, and tidy apply only to .html output.
The output path, or (when output is NA) the HTML as a string.
When the option lt.lt_static is set to a list of arguments (e.g.,
options(lt.lt_static = list(css = FALSE))), the
knit_print and record_print
methods emit the same static HTML table as lt_export(x, "*.html") (using
those arguments as method/css/fragment) instead of the default
JavaScript-based spec. This is useful for output formats that support raw
HTML but cannot run JavaScript (e.g., GitHub Flavored Markdown).
tbl = lt(head(mtcars)) # HTML with the JavaScript spec (table built by lt.js when viewed) f1 = tempfile(fileext = '.html') lt_export(tbl, f1, method = 'raw') # file output # Bake a static <table> (needs Node.js or a headless browser). if (lt:::can_bake()) lt_export(tbl, NA, method = 'auto', fragment = TRUE, css = FALSE, tidy = TRUE) # PDF / PNG are rendered in a headless browser and cropped to the table. f2 = tempfile(fileext = '.pdf') f3 = tempfile(fileext = '.png') if (lt:::has_browser()) { lt_export(tbl, f2) lt_export(tbl, f3, width = 400) } unlink(c(f1, f2, f3))tbl = lt(head(mtcars)) # HTML with the JavaScript spec (table built by lt.js when viewed) f1 = tempfile(fileext = '.html') lt_export(tbl, f1, method = 'raw') # file output # Bake a static <table> (needs Node.js or a headless browser). if (lt:::can_bake()) lt_export(tbl, NA, method = 'auto', fragment = TRUE, css = FALSE, tidy = TRUE) # PDF / PNG are rendered in a headless browser and cropped to the table. f2 = tempfile(fileext = '.pdf') f3 = tempfile(fileext = '.png') if (lt:::has_browser()) { lt_export(tbl, f2) lt_export(tbl, f3, width = 400) } unlink(c(f1, f2, f3))
Attaches a footnote text to a table region. Footnotes are numbered
automatically in the order they are added (de-duplicated by text).
lt_footnote(x, text, where, columns = NULL, rows = NULL, match = NULL)lt_footnote(x, text, where, columns = NULL, rows = NULL, match = NULL)
x |
An |
text |
Footnote text. |
where |
One of |
columns |
Character names, integer positions, or a one-sided formula
(for |
rows |
Integer vector of 1-based row indices (for |
match |
For |
x with the footnote recorded.
lt(head(mtcars)) |> lt_footnote("Source: 1974 Motor Trend US magazine.", "title") # raw HTML footnote (wrap in I()) lt(head(mtcars)) |> lt_footnote(I("See <a href='#'>docs</a>."), "title") # a footnote for each of the six locations d = data.frame( Arm = c("Treatment", "Treatment", "Control", "Control"), Stat = c("n", "Mean", "n", "Mean"), Value = c(31, 6.8, 30, 4.2), SE = c(NA, 0.42, NA, 0.38) ) lt(d) |> lt_group(~ Arm) |> lt_header(title = "Study Results", subtitle = "Two arms") |> lt_spanner(Summary ~ Value + SE) |> lt_footnote("Source: simulated trial data.", "title") |> lt_footnote("Intention-to-treat population.", "subtitle") |> lt_footnote("Standard error of the mean.", "column", "SE") |> lt_footnote("Per-arm summary statistics.", "spanner", "Summary") |> lt_footnote("Received active drug.", "group", "Treatment") |> lt_footnote("SE undefined for counts.", "body", "SE", rows = c(1, 3))lt(head(mtcars)) |> lt_footnote("Source: 1974 Motor Trend US magazine.", "title") # raw HTML footnote (wrap in I()) lt(head(mtcars)) |> lt_footnote(I("See <a href='#'>docs</a>."), "title") # a footnote for each of the six locations d = data.frame( Arm = c("Treatment", "Treatment", "Control", "Control"), Stat = c("n", "Mean", "n", "Mean"), Value = c(31, 6.8, 30, 4.2), SE = c(NA, 0.42, NA, 0.38) ) lt(d) |> lt_group(~ Arm) |> lt_header(title = "Study Results", subtitle = "Two arms") |> lt_spanner(Summary ~ Value + SE) |> lt_footnote("Source: simulated trial data.", "title") |> lt_footnote("Intention-to-treat population.", "subtitle") |> lt_footnote("Standard error of the mean.", "column", "SE") |> lt_footnote("Per-arm summary statistics.", "spanner", "Summary") |> lt_footnote("Received active drug.", "group", "Treatment") |> lt_footnote("SE undefined for counts.", "body", "SE", rows = c(1, 3))
Control the number of decimal places and thousands separator for numeric
columns. Columns passed to this function are excluded from automatic
formatting (see the auto_format argument of lt()). To disable auto-format
for a column without otherwise changing its display, call lt_format(x, ~col) with no other arguments.
lt_format( x, columns, decimals = NULL, sig_digits = NULL, big_mark = NULL, percent = NULL, prefix = NULL, suffix = NULL )lt_format( x, columns, decimals = NULL, sig_digits = NULL, big_mark = NULL, percent = NULL, prefix = NULL, suffix = NULL )
x |
An |
columns |
Columns to select: a character vector of column names,
integer positions, or a one-sided formula. A formula whose right-hand side
references the pronoun |
decimals |
Number of decimal places (default |
sig_digits |
Number of significant digits (e.g., |
big_mark |
Thousands separator (e.g., |
percent |
If |
prefix |
String prepended to each formatted value (e.g., |
suffix |
String appended to each formatted value (e.g., |
x with the formatting recorded.
lt(head(mtcars)) |> lt_format(~ mpg + wt, decimals = 1, big_mark = ",") d = data.frame(Item = c("A", "B"), Price = c(1234.5, 678.9)) lt(d) |> lt_format(~ Price, decimals = 2, big_mark = ",", prefix = "$") lt(d) |> lt_format(~ Price, sig_digits = 3)lt(head(mtcars)) |> lt_format(~ mpg + wt, decimals = 1, big_mark = ",") d = data.frame(Item = c("A", "B"), Price = c(1234.5, 678.9)) lt(d) |> lt_format(~ Price, decimals = 2, big_mark = ",", prefix = "$") lt(d) |> lt_format(~ Price, sig_digits = 3)
Partition rows into labeled groups. Pass column names to group by those
columns' values (the columns are removed from the body and rendered as
rowspan cells on the left). Use sep = TRUE to render groups as
full-width separator rows instead of rowspan.
lt_group(x, ..., sep = "auto", sort = TRUE)lt_group(x, ..., sep = "auto", sort = TRUE)
x |
An |
... |
A column name, integer position, or formula (e.g., |
sep |
If |
sort |
If |
x with the row groups recorded.
# Group by a column (rowspan, default) d = data.frame(arm = c("Placebo", "Placebo", "Treatment", "Treatment"), stat = c("n", "Mean", "n", "Mean"), value = c(30, 4.2, 31, 6.8)) lt(d) |> lt_group(~ arm) # Separator-row style lt(d) |> lt_group(~ arm, sep = TRUE) # Manual groups (always separator rows) lt(head(mtcars)) |> lt_group("First three" = 1:3, "Last three" = 4:6)# Group by a column (rowspan, default) d = data.frame(arm = c("Placebo", "Placebo", "Treatment", "Treatment"), stat = c("n", "Mean", "n", "Mean"), value = c(30, 4.2, 31, 6.8)) lt(d) |> lt_group(~ arm) # Separator-row style lt(d) |> lt_group(~ arm, sep = TRUE) # Manual groups (always separator rows) lt(head(mtcars)) |> lt_group("First three" = 1:3, "Last three" = 4:6)
Add a title and subtitle
lt_header(x, title = NULL, subtitle = NULL)lt_header(x, title = NULL, subtitle = NULL)
x |
An |
title |
A character scalar. Wrap in |
subtitle |
A character scalar. Wrap in |
x with the header recorded.
lt(head(mtcars)) |> lt_header("Motor Trend Cars", "First 6 rows") # raw HTML title lt(head(mtcars)) |> lt_header(I("<em>Motor Trend</em> Cars"))lt(head(mtcars)) |> lt_header("Motor Trend Cars", "First 6 rows") # raw HTML title lt(head(mtcars)) |> lt_header(I("<em>Motor Trend</em> Cars"))
Drop columns from the rendered table without removing them from the data.
The values still travel to the client in the spec, so they remain available
to things that read the whole row, such as an interactive table's row detail
(see the detail argument of lt_interactive()).
lt_hide(x, columns)lt_hide(x, columns)
x |
An |
columns |
Columns to select: a character vector of column names,
integer positions, or a one-sided formula. A formula whose right-hand side
references the pronoun |
x with the hidden columns recorded.
lt(head(mtcars)) |> lt_hide(~ gear + carb)lt(head(mtcars)) |> lt_hide(~ gear + carb)
Mark whole columns so their body cells are emitted as raw HTML instead of
being escaped. By default every cell is HTML-escaped (so <, >, and &
render as literal text); use this to embed links, emphasis, or other markup
in a column's cells.
lt_html(x, columns)lt_html(x, columns)
x |
An |
columns |
Columns whose cells are raw HTML: character names, integer
positions, or a one-sided formula (predicate formulas such as
|
To emit raw HTML in other regions (title, column labels, footnotes, ...),
wrap the text in I() in the corresponding lt_*() function instead.
x with the raw-HTML columns recorded.
d = data.frame( name = c("<a href='#a'>A</a>", "<a href='#b'>B</a>"), n = 1:2 ) lt(d) |> lt_html(~ name)d = data.frame( name = c("<a href='#a'>A</a>", "<a href='#b'>B</a>"), n = 1:2 ) lt(d) |> lt_html(~ name)
Add hierarchical indentation to the first column of specified rows.
lt_indent(x, rows, level = 1)lt_indent(x, rows, level = 1)
x |
An |
rows |
Integer vector of 1-based row indices to indent. |
level |
Indent level (default 1). Each level adds one unit of left padding. |
x with the indentation recorded.
d = data.frame(label = c("Overall", "Male", "Female"), n = c(100, 55, 45)) lt(d) |> lt_indent(2:3)d = data.frame(label = c("Overall", "Male", "Female"), n = c(100, 55, 45)) lt(d) |> lt_indent(2:3)
Make a table interactive in the browser: pagination, a table-wide search box, click-to-sort column headers, per-column filter boxes, and resizable columns. The features are handled client-side by an opt-in JavaScript extension, loaded only for tables that call this function.
lt_interactive( x, sort = TRUE, search = TRUE, filter = FALSE, pager = c(10, 25, 50, 100), resize = FALSE, hide = NULL, detail = NULL, download = FALSE )lt_interactive( x, sort = TRUE, search = TRUE, filter = FALSE, pager = c(10, 25, 50, 100), resize = FALSE, hide = NULL, detail = NULL, download = FALSE )
x |
An |
sort |
Whether clicking a column header sorts the table by that column
(cycling ascending, descending, then unsorted); shift-clicking adds a
column as a further tie-breaker, so several columns can sort at once.
Sorting uses the raw values, so numeric columns sort numerically. Can also
request an initial sort by one or more columns, given either as a character
vector of column names or as a one-sided formula (e.g. |
search |
Whether to show a table-wide search box. A row is kept when
any cell matches the term. Besides plain substring matching, a term that
references the cell variable |
filter |
The per-column filters. |
pager |
The page sizes to offer, as a vector of row counts; the
first one is used initially. Paging shows that many of the filtered and
sorted rows at a time, with a pager (first, previous, next, last), the row
range, and (for more than one size) a selector below the table. |
resize |
Whether to let the reader drag a column's right edge to resize
it (double-clicking the edge fits the column to its content). Widening a
column widens the table, leaving the other columns as they are. Initial
widths can be set with |
hide |
Column-visibility control: an eye button at the start of the
search row opens a checklist of every column, where unchecking a column
hides it (header and cells) and re-checking restores it. |
detail |
Row detail (drill-down). An expand caret is added to each row;
clicking it reveals a table built from that row below it. Give the columns
to show, as a character vector of names or a one-sided formula (e.g.
|
download |
Whether to add a button that downloads the table as a CSV
file. The file holds the current view (every row the filters and search
keep, in sort order, across all pages) of the table's columns. |
Sorting and filtering respect the row structure, happening within each
group or subtree rather than across it. Separator row groups (lt_group()
with sep = TRUE, or manual groups) keep their order, and a group whose rows
all filter out drops its header. Indentation (lt_indent()) sorts siblings
under each parent, and an indented child keeps its ancestors visible for
context. Rowspan row groups (lt_group() with its default rowspan rendering)
sort and filter within each run and clicking a group header reorders its
blocks; with several group columns the view stays nested (an inner column
reorders only within its parent block), and the spanning cells are redrawn to
match.
x with interactivity enabled.
lt(head(mtcars)) |> lt_interactive() # search only, no click-to-sort or pagination lt(head(mtcars)) |> lt_interactive(sort = FALSE, pager = FALSE) # 5 rows at a time, or all of them, with a filter box on one column lt(mtcars) |> lt_interactive(filter = 'cyl', pager = c(5, Inf)) # resizable columns lt(head(mtcars)) |> lt_interactive(resize = TRUE) # a column-visibility menu (all columns shown, or with some hidden to start) lt(head(mtcars)) |> lt_interactive(hide = TRUE) lt(head(mtcars)) |> lt_interactive(hide = ~ hp + drat) # an initial sort by cyl, then mpg descending within each lt(mtcars) |> lt_interactive(sort = ~ cyl + -mpg) # expandable row detail (drill-down): name the columns to show. Here gear and # carb are hidden from the main table but revealed in the detail that appears # when a row is expanded. lt(head(mtcars)) |> lt_hide(~ gear + carb) |> lt_interactive(detail = ~ gear + carb) # for full control, pass a JavaScript callback yourself: (raw row, index, # displayed row); here showing the row number and mpg as the table displays it lt(head(mtcars)) |> lt_interactive( detail = js('(row, i, d) => ({ data: { metric: ["row", "mpg"], value: [i, d.mpg] } })') ) # a button to download the current view as a CSV file lt(head(mtcars)) |> lt_interactive(download = TRUE) lt(head(mtcars)) |> lt_interactive(download = 'cars.csv') # export the raw (unformatted) values instead of the displayed text lt(head(mtcars)) |> lt_interactive(download = list(file = 'cars.csv', mode = 'raw'))lt(head(mtcars)) |> lt_interactive() # search only, no click-to-sort or pagination lt(head(mtcars)) |> lt_interactive(sort = FALSE, pager = FALSE) # 5 rows at a time, or all of them, with a filter box on one column lt(mtcars) |> lt_interactive(filter = 'cyl', pager = c(5, Inf)) # resizable columns lt(head(mtcars)) |> lt_interactive(resize = TRUE) # a column-visibility menu (all columns shown, or with some hidden to start) lt(head(mtcars)) |> lt_interactive(hide = TRUE) lt(head(mtcars)) |> lt_interactive(hide = ~ hp + drat) # an initial sort by cyl, then mpg descending within each lt(mtcars) |> lt_interactive(sort = ~ cyl + -mpg) # expandable row detail (drill-down): name the columns to show. Here gear and # carb are hidden from the main table but revealed in the detail that appears # when a row is expanded. lt(head(mtcars)) |> lt_hide(~ gear + carb) |> lt_interactive(detail = ~ gear + carb) # for full control, pass a JavaScript callback yourself: (raw row, index, # displayed row); here showing the row number and mpg as the table displays it lt(head(mtcars)) |> lt_interactive( detail = js('(row, i, d) => ({ data: { metric: ["row", "mpg"], value: [i, d.mpg] } })') ) # a button to download the current view as a CSV file lt(head(mtcars)) |> lt_interactive(download = TRUE) lt(head(mtcars)) |> lt_interactive(download = 'cars.csv') # export the raw (unformatted) values instead of the displayed text lt(head(mtcars)) |> lt_interactive(download = list(file = 'cars.csv', mode = 'raw'))
Override column headers without modifying the underlying data frame.
lt_label(x, ...)lt_label(x, ...)
x |
An |
... |
Named arguments of the form |
x with the column label overrides recorded.
lt(head(mtcars)) |> lt_label(mpg = "Miles/Gallon", cyl = "Cylinders") # raw HTML label (wrap in I()) lt(head(mtcars)) |> lt_label(mpg = I("Miles/Gallon<sup>*</sup>")) # a single named list or vector of labels lt(head(mtcars)) |> lt_label(c(mpg = "Miles/Gallon", cyl = "Cylinders")) # a single list(names, labels) of two parallel vectors lt(head(mtcars)) |> lt_label(list(c("mpg", "cyl"), c("Miles/Gallon", "Cylinders")))lt(head(mtcars)) |> lt_label(mpg = "Miles/Gallon", cyl = "Cylinders") # raw HTML label (wrap in I()) lt(head(mtcars)) |> lt_label(mpg = I("Miles/Gallon<sup>*</sup>")) # a single named list or vector of labels lt(head(mtcars)) |> lt_label(c(mpg = "Miles/Gallon", cyl = "Cylinders")) # a single list(names, labels) of two parallel vectors lt(head(mtcars)) |> lt_label(list(c("mpg", "cyl"), c("Miles/Gallon", "Cylinders")))
Combine values from multiple columns into a single display column using a pattern. Source columns (all except the first) are hidden by default.
lt_merge(x, columns, pattern = NULL, hide = TRUE)lt_merge(x, columns, pattern = NULL, hide = TRUE)
x |
An |
columns |
Character names, integer positions, or a one-sided formula
(predicate formulas such as |
pattern |
A glue-style template using |
hide |
If |
x with the merge recorded.
d = data.frame(stat = c("Mean", "SD"), value = c(4.2, 1.1), ci = c("(2.0, 6.4)", "(0.5, 1.7)")) lt(d) |> lt_merge(~ value + ci, pattern = "{1} {2}")d = data.frame(stat = c("Mean", "SD"), value = c(4.2, 1.1), ci = c("(2.0, 6.4)", "(0.5, 1.7)")) lt(d) |> lt_merge(~ value + ci, pattern = "{1} {2}")
Rearrange column display order without modifying the data frame.
lt_move(x, columns, after = NULL)lt_move(x, columns, after = NULL)
x |
An |
columns |
Columns to select: a character vector of column names,
integer positions, or a one-sided formula. A formula whose right-hand side
references the pronoun |
after |
Column name or integer position after which to place the
moved columns. Use |
x with the column move recorded.
lt(head(mtcars)) |> lt_move(~ gear + carb, after = "mpg")lt(head(mtcars)) |> lt_move(~ gear + carb, after = "mpg")
Notes are rendered in the table footer below numbered footnotes.
lt_note(x, text)lt_note(x, text)
x |
An |
text |
Note text. Wrap in |
x with the note recorded.
lt(head(mtcars)) |> lt_note("CI = confidence interval.") # raw HTML note (wrap in I()) lt(head(mtcars)) |> lt_note(I("CI = <em>confidence interval</em>."))lt(head(mtcars)) |> lt_note("CI = confidence interval.") # raw HTML note (wrap in I()) lt(head(mtcars)) |> lt_note(I("CI = <em>confidence interval</em>."))
lt_output() creates a UI placeholder; render_lt() supplies the table
spec from the server. Together they render an lt() table as a custom
Shiny output — no renderUI() involved.
lt_output(outputId, ...) render_lt(expr, env = parent.frame(), quoted = FALSE)lt_output(outputId, ...) render_lt(expr, env = parent.frame(), quoted = FALSE)
outputId |
Output variable name to read the table from. |
... |
Reserved for future use. |
expr |
An expression that returns an |
env |
Environment in which to evaluate |
quoted |
Whether |
lt_output() returns a Shiny UI element; render_lt() returns a
render function.
if (interactive()) { library(shiny) ui = fluidPage(lt_output("tbl")) server = function(input, output) { output$tbl = render_lt(lt(head(mtcars)) |> lt_header("Motor Trend")) } shinyApp(ui, server) }if (interactive()) { library(shiny) ui = fluidPage(lt_output("tbl")) server = function(input, output) { output$tbl = render_lt(lt(head(mtcars)) |> lt_header("Motor Trend")) } shinyApp(ui, server) }
A spanner is a label rendered above a contiguous group of column headers.
lt_spanner(x, label, columns, sep = "[._]")lt_spanner(x, label, columns, sep = "[._]")
x |
An |
label |
A character scalar — the spanner text. Alternatively, a
two-sided formula |
columns |
Columns to span: character names, integer positions, or a
one-sided formula (predicate formulas such as |
sep |
Separator pattern for auto-inference (default |
When called with no label or columns, infers spanners from column
names by splitting on the first . or _ separator. Contiguous columns
sharing a prefix are grouped under that prefix, and column labels are
shortened to the suffix.
x with the spanner recorded.
The columns must be contiguous in the body of the table.
tbl = lt(head(iris)) # Explicit spanner tbl |> lt_spanner(Sepal ~ Sepal.Length + Sepal.Width) # Auto-infer from column names tbl |> lt_spanner() # raw HTML label (wrap in I()) tbl |> lt_spanner(I("<em>Sepal</em>"), ~ Sepal.Length + Sepal.Width)tbl = lt(head(iris)) # Explicit spanner tbl |> lt_spanner(Sepal ~ Sepal.Length + Sepal.Width) # Auto-infer from column names tbl |> lt_spanner() # raw HTML label (wrap in I()) tbl |> lt_spanner(I("<em>Sepal</em>"), ~ Sepal.Length + Sepal.Width)
Render a per-row series of numbers as a small inline SVG line or bar chart (a
sparkline). The series for each row can come from a single list-column (each
element a numeric vector) or from several numeric columns read across the
row. Like lt_errorbar(), it is lightweight: only the numbers travel to the
client and the SVG is drawn in the browser, so an interactive table
(lt_interactive()) draws only the rows on the current page.
lt_sparkline( x, columns, type = c("line", "bar"), limits = NULL, color = NULL, width = 120, height = 20, hide = TRUE )lt_sparkline( x, columns, type = c("line", "bar"), limits = NULL, color = NULL, width = 120, height = 20, hide = TRUE )
x |
An |
columns |
The column(s) holding each row's series. Either a single
list-column (a one-sided formula |
type |
|
limits |
Numeric |
color |
CSS color for the line or bars (defaults to the stylesheet's). |
width, height
|
Pixel size of each cell's SVG. |
hide |
If |
x with the sparkline column recorded.
# a list-column: each cell is a numeric vector d = data.frame(city = c("A", "B", "C")) d$temp = list(c(3, 5, 8, 6, 9), c(1, 2, 2, 4, 3), c(7, 6, 5, 6, 8)) lt(d) |> lt_sparkline(~ temp) # several columns read across the row, as bars on a shared scale m = data.frame(name = c("X", "Y"), q1 = c(2, 5), q2 = c(4, 3), q3 = c(6, 7), q4 = c(5, 2)) lt(m) |> lt_sparkline(~ q1 + q2 + q3 + q4, type = "bar", limits = c(0, 8))# a list-column: each cell is a numeric vector d = data.frame(city = c("A", "B", "C")) d$temp = list(c(3, 5, 8, 6, 9), c(1, 2, 2, 4, 3), c(7, 6, 5, 6, 8)) lt(d) |> lt_sparkline(~ temp) # several columns read across the row, as bars on a shared scale m = data.frame(name = c("X", "Y"), q1 = c(2, 5), q2 = c(4, 3), q3 = c(6, 7), q4 = c(5, 2)) lt(m) |> lt_sparkline(~ q1 + q2 + q3 + q4, type = "bar", limits = c(0, 8))
Return the JSON-ready spec for an lt() table: the raw data plus the
declarative ops (and any lt_interactive() options), prepared exactly as the
JavaScript runtime expects. This is the payload the runtime consumes, so
another widget can embed an lt table by shipping this spec (e.g.
xfun::tojson(lt_spec(x))) and rendering it client-side on demand with
LT.render(container, spec) (or LT.buildHtml(spec)). Styling from
lt_css() and CSS rules is dropped; attach the runtime assets separately
(see lt_dependency()).
lt_spec(x)lt_spec(x)
x |
An |
A named list of spec fields (data, ops, and any others set on the
table), ready to serialize to JSON.
spec = lt_spec(lt(head(mtcars)) |> lt_interactive()) str(spec, max.level = 1) xfun::tojson(spec) # ship this, then LT.render(container, spec) in the browserspec = lt_spec(lt(head(mtcars)) |> lt_interactive()) str(spec, max.level = 1) xfun::tojson(spec) # ship this, then LT.render(container, spec) in the browser
Apply CSS styling to specific cells. Target cells by column, row, or both.
When test is provided, styles are applied conditionally based on cell
values (evaluated in JavaScript).
lt_style( x, columns = NULL, rows = NULL, test = NULL, class = NULL, bold = NULL, italic = NULL, color = NULL, bg = NULL, ... )lt_style( x, columns = NULL, rows = NULL, test = NULL, class = NULL, bold = NULL, italic = NULL, color = NULL, bg = NULL, ... )
x |
An |
columns |
Character names, integer positions, a one-sided formula
(predicate formulas such as |
rows |
Integer vector of 1-based row indices (or |
test |
A JavaScript function as a string (e.g., |
class |
CSS class name(s) to add to matching cells. Define the
corresponding rules in an external stylesheet via |
bold |
Logical: apply bold weight? |
italic |
Logical: apply italic style? |
color |
Text color (any CSS color value, e.g., |
bg |
Background color. |
... |
Additional CSS properties as named arguments. Names can be
camelCase (e.g., |
x with the style recorded.
tbl = lt(head(mtcars)) tbl |> lt_style("mpg", rows = 1L, bold = TRUE, borderBottom = "2px solid red") tbl |> lt_style("mpg", test = "v => v > 20", class = "high") |> lt_css(.high = list(background = "#cfc"))tbl = lt(head(mtcars)) tbl |> lt_style("mpg", rows = 1L, bold = TRUE, borderBottom = "2px solid red") tbl |> lt_style("mpg", test = "v => v > 20", class = "high") |> lt_css(.high = list(background = "#cfc"))
Replace NA, zero, or small values with display text.
lt_sub( x, columns = NULL, missing = NULL, zero = NULL, small = NULL, small_text = NULL )lt_sub( x, columns = NULL, missing = NULL, zero = NULL, small = NULL, small_text = NULL )
x |
An |
columns |
Character names, integer positions, a one-sided formula
(predicate formulas such as |
missing |
Replacement for |
zero |
Replacement for zero values (e.g., |
small |
Threshold: values whose absolute value is below this are
replaced by |
small_text |
Text shown for values below |
x with the substitution recorded.
d = data.frame(x = c(1, 0, NA, 0.001)) lt(d) |> lt_sub(missing = "n/a", zero = "—", small = 0.01, small_text = "<0.01")d = data.frame(x = c(1, 0, NA, 0.001)) lt(d) |> lt_sub(missing = "n/a", zero = "—", small = 0.01, small_text = "<0.01")
Set column and table widths
lt_width(x, ...)lt_width(x, ...)
x |
An |
... |
Named arguments of the form |
x with the widths recorded.
lt(head(mtcars)) |> lt_width(mpg = "100px", cyl = "50px") # set the whole-table width, optionally with column widths lt(head(mtcars)) |> lt_width("80%", mpg = "100px") # a single list(names, widths) of two parallel vectors lt(head(mtcars)) |> lt_width(list(c("mpg", "cyl"), c("100px", "50px")))lt(head(mtcars)) |> lt_width(mpg = "100px", cyl = "50px") # set the whole-table width, optionally with column widths lt(head(mtcars)) |> lt_width("80%", mpg = "100px") # a single list(names, widths) of two parallel vectors lt(head(mtcars)) |> lt_width(list(c("mpg", "cyl"), c("100px", "50px")))
Set arbitrary HTML attributes on the <div class="lt-wrap"> that wraps the
rendered table (e.g. style, id, data-*). A class is appended to the
base lt-wrap class rather than replacing it, and accumulates across repeated
calls. Common uses are scoping custom CSS (e.g. attached with lt_css()) to
this table alone, or giving the container a fixed width.
lt_wrap(x, ...)lt_wrap(x, ...)
x |
An |
... |
Named HTML attributes for the container, e.g. |
x with the container attributes recorded.
lt(head(mtcars)) |> lt_wrap(class = "my-table", style = "width:400px")lt(head(mtcars)) |> lt_wrap(class = "my-table", style = "width:400px")
lt_tbl (opens in the viewer or browser)Print an lt_tbl (opens in the viewer or browser)
## S3 method for class 'lt_tbl' print(x, ...)## S3 method for class 'lt_tbl' print(x, ...)
x |
An |
... |
Passed to |
x, invisibly.
print(lt(head(mtcars)))print(lt(head(mtcars)))