What is ksTFL?
ksTFL is a lightweight R toolkit for building metadata specifications for clinical Tables, Figures, and Text (TFLs). Unlike traditional table formatters (flextable, huxtable, officer), ksTFL separates metadata generation from rendering:
- You define: Document structure, content, column formats, and styles in R
- ksTFL generates: A structured specification (JSON metadata + data files)
- Built-in C++ renderer: Produces submission-quality
DOCX documents with deterministic HarfBuzz-based pagination via
write_doc() / replay_report()
This separation enables:
- Consistency: All tables follow the same style templates
- Automation: Generate 50+ tables with consistent formatting and minimal code
- Reproducibility: Specifications are version-controllable and auditable
- Flexibility: Swap renderers without changing your R code
When to use ksTFL:
- Regulatory clinical reporting (FDA, EMA submissions) - Large-scale automated reporting (100+ tables from common data sources)
- Complex styling requirements (multi-level headers, spanning columns, conditional formatting) - When you need JSON metadata for downstream processing
This is the foundation vignette and best starting point for new users. It introduces the core objects, the main function flow, and the smallest complete pipeline needed to create, assemble, and render reports confidently.
Recommended reading order after this vignette:
1. Reporting Examples and FAQ for the quickest practical follow-up.
2. Styling Guide, Column Width Management, and Advanced StyleRows for focused feature depth.
3. Real Examples for fuller clinical-style outputs, then Font Management and Rendering Pipeline when you need environment or renderer internals.
Data Frame / Image File
↓
create_table() / create_figure() / create_text()
↓
TFL_spec (customize with define_cols(), add_style(), add_title(), compute_cols())
↓
create_report() (assemble specs, consolidate styles)
↓
TFL_report
↓
write_doc() ← recommended: one-step save + render
or
save_report() → replay_report() ← two-step: inspect JSON before rendering
↓
Styled .docx (C++ engine, deterministic HarfBuzz pagination)
Each TFL_spec contains:
| Component | Purpose | How to modify |
|---|---|---|
| document | Metadata (docType, title, page settings) | set_document(), set_page_style() |
| columns | Column definitions, labels, formats, styles | define_cols() |
| stubColumns | Spanning headers above column groups | add_span_header() |
| headers | Page header text (left/center/right) | add_header() |
| titles | Main document titles | add_title() |
| subtitles | Secondary titles | add_subtitle() |
| bodyText | Narrative content | add_body_text() |
| footnotes | Document footnotes | add_footnote() |
| footers | Page footer text | add_footer() |
| styles | Named styles defined with add_style() |
add_style() |
Get a working spec in 5 minutes:
library(ksTFL)
# 1. Create a table spec from data
spec <- create_table(mtcars, cols = c(mpg, cyl, hp))
# 2. Define a style and apply it
spec <- add_style(spec, id = "header_bold",
s_font(bold = TRUE, font_size = "12pt"))
# 3. Customize columns
spec <- define_cols(spec, c(mpg, cyl, hp),
label = c("MPG", "Cylinders", "HP"),
type = c("numeric", "numeric", "numeric"),
format = c("%.1f", "%.0f", "%.0f"),
labelStyleRef = "header_bold") |>
# 4. Add titles and footnotes
add_title("Motor Trends Dataset") |>
add_footnote("Data from mtcars (1974).")
# 5. Inspect the spec
print(spec)
# 6. Render to DOCX
report <- create_report(spec)
write_doc(report, name = "my_table", outDir = "./output", metaPath = tempdir())Choose the document type and initialize:
# Simple: all columns
spec_tbl <- create_table(mtcars)
# Select specific columns with tidyselect
spec_tbl <- create_table(mtcars, cols = c(mpg, cyl, hp, wt))What happens:
- Data is shadow-copied into the spec’s internal environment (not modifiable)
- Columns are auto-analyzed (type detection, width calculation)
- A TFL_spec object is returned ready for
customization
Understanding the cols parameter:
The cols argument controls which columns appear in the
rendered document and in what order — it does not
filter or mutate the input data frame. Think of it as a presentation
lens: the full dataset is still stored inside the spec, but only
the columns listed in cols are emitted to the final
report.
This distinction matters when you use compute_cols()
later in the pipeline. Because the original data frame is preserved
intact, compute_cols() conditions can reference
any column in the data — including columns that are
not listed in cols and will never appear
in the output. For example, you might exclude a flag column
from the report but still use it to drive conditional styling:
# Only age, sex, trt go to the document; flag stays hidden
spec <- create_table(demog, cols = c(age, sex, trt))
# But flag is still available for conditional logic
spec <- compute_cols(spec, trt,
c_style("highlight"),
when = flag == "Y")The order in which columns are passed to cols also
determines their left-to-right order in the rendered table, so
cols doubles as a convenient column-reordering mechanism —
no need to rearrange the underlying data frame.
# From a file path — any image format your renderer supports (PNG, JPEG, etc.)
spec_fig <- create_figure("path/to/plot.png")
# From a ggplot2 object — rendered automatically to a temporary image file
library(ggplot2)
p <- ggplot(mtcars, aes(x = wt, y = mpg)) + geom_point()
spec_fig <- create_figure(p) # uses configured defaults
spec_fig <- create_figure(p, dpi = 150L) # custom resolution (dpi)
# Control output size/format via options
# tfl_set_options(figureWidth = "8in", figureHeight = "5in", figureDevice = "jpeg")
# spec_fig <- create_figure(p)What happens:
- If a file path is given: it is validated (must exist and be readable); the file is used as-is
- If a ggplot2 object is given: rendered via
ggplot2::ggsave() to tempdir() using package
defaults (figureWidth, figureHeight,
figureDevice); the resulting path is stored in the spec
- The dpi parameter applies when a ggplot2 object is
passed; width/height/device are configured through package options
- The image file is copied to metaPath when the report
is saved
After creating a table spec, customize columns with
define_cols():
# Different format for each column
spec <- define_cols(spec, c(mpg, cyl, hp),
label = c("MPG", "Cylinders", "HP"),
type = c("numeric", "numeric", "numeric"),
format = c("%.1f", "%.0f", "%.0f"))Key parameters:
- label: Column header text
- type: “numeric” or “string” (auto-detected if
omitted)
- format: Format string (e.g., “%.2f”, “0.00”)
- colWidth: Column width (e.g., “20%”, “2cm”) - When
set, column is locked to that width - Other unlocked columns
auto-recalculate to sum to 100% - Disable auto-recalculation with
tfl_set_options(autoColWidth = FALSE)
- isVisible: TRUE (default) or FALSE - Set to FALSE to
hide column from output - Invisible columns show width “0.0cm” - Cannot
set colWidth on invisible columns - Invisible columns excluded from
width recalculation
- isID: TRUE if column repeats on page breaks
- dedupe: TRUE to clear consecutive repeating values in
a column
- isColBreak: TRUE on a column that needs to be moved on
the next page (break long tables)
- labelStyleRef: Style(s) to apply to column header
- valueStyleRef: Style(s) to apply to cell values
Hiding Columns:
# Hide a column (e.g., for conditional logic that doesn't display)
spec <- create_table(data) |>
define_cols(group_id, isVisible = FALSE)
# Result: group_id is hidden, other columns recalculated to fill 100%See Reporting Examples for detailed column customization patterns.
Create reusable named styles with add_style():
spec <- create_table(mtcars)
# Header style: bold, 12pt, centered, gray background
spec <- add_style(spec, id = "table_header",
s_font(font_name = "Arial", font_size = "12pt", bold = TRUE),
s_paragraph(alignment = "center"),
s_table_style(background_color = "#E0E0E0"))
# Numeric style: right-aligned
spec <- add_style(spec, id = "numeric_right",
s_paragraph(alignment = "right"))
# Apply to columns
spec <- define_cols(spec, c(mpg, hp),
labelStyleRef = "table_header",
valueStyleRef = "numeric_right")Best practice: Define styles once, reference by id
(name) throughout your spec. If style needs to be used across many
tables define it thru tfl_set_options() to make it
available session-wide.
For comprehensive styling details see Styling Guide.
Create multi-level headers with add_span_header() using
tidyselect expressions:
spec <- create_table(mtcars)
spec <- define_cols(spec, c(mpg, cyl, hp, wt),
label = c("MPG", "Cyl", "HP", "Weight"))
# Top-level span header spanning all columns
spec <- add_span_header(spec, cols = c(mpg, cyl, hp, wt),
label = "Motor Vehicle Specs",
stubOrder = 0) |>
# Second-level headers: finer grouping
add_span_header(cols = c(mpg, cyl, hp),
label = "Engine",
stubOrder = 1) |>
add_span_header(cols = wt,
label = "Weight",
stubOrder = 1)Tidyselect support: add_span_header()
accepts all tidyselect expressions:
# Using column ranges and helpers
spec <- add_span_header(spec, cols = mpg:hp, label = "First", stubOrder = 0) |>
add_span_header(cols = starts_with("c"), label = "C-columns", stubOrder = 1) |>
add_span_header(cols = -mpg, label = "Non-MPG", stubOrder = 2)Key concepts:
- cols: Column names (from spec$columns) to
span.
Accepts:
- Unquoted names: c(mpg, cyl, hp)
- Quoted names:
c("mpg", "cyl", "hp")
- Ranges: mpg:hp
- Helpers: starts_with("c"),
contains("w"), matches("^m")
- Negation: -mpg (all columns except
mpg)
- label: Spanning header text
- stubOrder: Vertical stacking order (1 = top, 2 = next,
etc.; auto-generated if NULL)
- labelStyleRef: Style(s) for the header label
Rules:
- Stubs at the same stubOrder cannot
share columns (prevents ambiguous headers)
- Stubs at different stubOrder values
can overlap freely (enables hierarchical structure)
- Multiple stubs at the same order are allowed as long as their column sets don’t overlap
- Use add_style() to style stub labels or use embedded
atomic styles
See Styling Guide for styling stubs.
Use set_page_style() with p_page() and
p_margins() to control the physical page layout:
spec <- create_table(mtcars) |>
set_page_style(
page = p_page(
size = "A4", # "A4", "Letter", or "Legal"
orientation = "landscape", # "portrait" or "landscape"
margins = p_margins(
top = "1in",
bottom = "1in",
left = "0.75in",
right = "0.75in",
header = "0.5in",
footer = "0.5in"
)
)
)p_page() parameters:
- size: Page size — "A4" (default),
"Letter", or "Legal"
- orientation: "portrait" (default) or
"landscape"
- margins: A margins object from
p_margins()
p_margins() parameters (all accept
dimension strings like "1in", "2.54cm",
"72pt", "25.4mm"):
- top, bottom, left,
right: Page margins
- header, footer: Distance from page edge
to header/footer content
Templates control the visual appearance (colours, fonts, borders) of the rendered DOCX:
# List all bundled templates
tfl_list_templates()
# Apply a bundled template
spec <- create_table(mtcars) |>
set_page_style(docTemplate = "Navy_Pro")
# Or apply via set_document()
spec <- create_table(mtcars) |>
set_document(hasData = TRUE, docTemplate = "Carbon_Dark")
# Use a custom external template (JSON file)
spec <- create_table(mtcars) |>
set_page_style(docTemplate = "path/to/my_custom_template.json")Use docTemplate on the spec when different sections of
one report should keep different looks. Use
write_doc(..., overrideTemplate = ...) or
replay_report(..., overrideTemplate = ...) when you want
one global template to override every spec in the rendered document.
Use run_styles_editor() to interactively create and edit
template JSON files.
Assemble multiple specs with create_report():
# Create multiple specs
spec_table <- create_table(mtcars)
spec_table <- add_title(spec_table, "Table 1: Demographics")
spec_text <- create_text()
spec_text <- add_body_text(spec_text, "Analysis performed in R.")
spec_fig <- create_figure("plots/histogram.png")
# Combine into single report
report <- create_report(spec_table, spec_text, spec_fig)
# Inspect combined report
print(report)What create_report() does:
1. Flattens inputs — including plain list arguments (see
below)
2. Validates structure
3. Consolidates combined styles (if any used
f_combine())
4. Assigns sequential docOrder (1, 2, 3, …)
5. Creates dataRef names for new specs
You can also build specs into a named list and pass the whole list at once — useful when the set of outputs is assembled dynamically:
specs <- list(
t_dm = spec_table,
t_text = spec_text,
t_fig = spec_fig
)
report <- create_report(specs)
# names(report): "t_dm_<hash>", "t_text_<hash>", "t_fig_<hash>"List and variadic arguments may be freely mixed:
6. Returns a TFL_report object
Result: A single report combining all specs in input order. Additionally a Table of Contents can be auto-generated in such documents that allows to create a production ready TFL reports.
Beyond global column styling, apply conditional actions to specific rows that match a condition:
spec <- create_table(mtcars)
# Define a style for first group occurrences
spec <- add_style(spec, id = "group_header", s_font(bold = TRUE, color = "#0000FF"))
# Apply style conditionally: highlight first occurrence of each cyl group
spec <- compute_cols(spec, firstOf(cyl),
c_style(c(mpg, hp), styleRef = "group_header"))
# Add a separator row above first group
spec <- compute_cols(spec, firstOf(cyl),
c_addrow(pos = "above"))Common use cases: - Highlight group
headers: Style first/last occurrence of a group - Add
separators: Insert empty rows between groups - Merge
columns: Create group headers by merging columns -
Conditional formatting: Style rows meeting a threshold
(e.g., value > 100)
Key action functions (used inside
compute_cols()):
| Function | Purpose | Example |
|---|---|---|
c_style(cols, styleRef) |
Apply style to columns in matching rows | c_style(c(mpg, hp), styleRef = "bold") |
c_merge(cols, styleRef = NULL) |
Merge adjacent columns | c_merge(c(col1, col2), styleRef = "header") |
c_addrow(pos, value_from = NULL, styleRef = NULL) |
Insert row above/below | c_addrow(pos = "above") for empty separator |
c_pageBreak() |
Insert a page break at the matching row (no args) | c_pageBreak() |
Condition syntax:
# Direct column comparison
compute_cols(spec, cyl > 6, c_style(mpg, styleRef = "emphasize"))
# String matching
compute_cols(spec, Parameter == "Pulse", c_style(value, styleRef = "numeric"))
# Helper functions available INSIDE compute_cols() conditions:
# firstOf(col1, col2, ...) — TRUE for first row of each unique combination
# lastOf(col1, col2, ...) — TRUE for last row of each unique combination
# firstRow() — TRUE only for the very first data row
# lastRow() — TRUE only for the very last data row
# everyNth(n) — TRUE every n-th row (1, n+1, 2n+1, ...)
# rowNumber() — 1-based row index
# firstOfBlock(col, n, offset) — first row of every n-th block
# Note: these helpers are NOT standalone functions — they only work inside
# the condition argument of compute_cols().
compute_cols(spec, firstOf(group), c_style(c(col1, col2), styleRef = "group_header"))
compute_cols(spec, lastOf(group), c_addrow(pos = "below"))
compute_cols(spec, everyNth(5), c_style(mpg, styleRef = "zebra"))
# Combine conditions
compute_cols(spec, cyl == 8 & hp > 100, c_style(mpg, styleRef = "high_power"))Key concepts:
- Conditions are evaluated during create_report() — at
that point, all data is available
- Multiple compute_cols() calls accumulate on the same
spec
- Actions on the same row from different compute_cols()
blocks are combined
- value_from = NULL in c_addrow() creates
an empty separator row
For detailed examples see Reporting Examples: Conditional Row Actions.
write_doc() (recommended)write_doc() combines save + render into a single
call:
report <- create_report(spec_table, spec_text)
# Returns the full path to the generated .docx (invisibly)
doc_path <- write_doc(report,
name = "demographics", # Output file name (no extension)
outDir = "./output", # Where the final .docx is written
metaPath = tempdir()) # Where JSON metadata is written (temp is fine)Additional parameters:
- toc: If TRUE, prepends a Table of
Contents page (requires toclevel on titles - see
?add_title)
- tocTitle: Heading above the TOC field (default
"Table of Contents")
- prettify: If TRUE, writes human-readable
JSON (useful for debugging)
- verbose: If TRUE, prints renderer
progress messages to R console
This is the recommended approach for production use. Set session defaults once:
save_report() +
replay_report()Use this when you need to inspect or version-control the JSON metadata separately:
report <- create_report(spec_table, spec_text)
# Step 1: Serialize to JSON + data files
result <- save_report(report,
docFileName = "my_report.docx",
outDir = "./output",
metaPath = tempdir(),
prettify = TRUE) # prettify = TRUE for readable JSON (debugging)
# Step 2: Re-render the DOCX from the saved JSON metadata
replay_report(
spec_json = result$spec_file,
meta_dir = result$metaPath,
output_path = file.path("./output", "my_report.docx"))save_report() output files:
- {metaPath}/{spec_hash}.json — Main specification
(consumed by renderer)
- {metaPath}/{dataRef}.json — Table data files (one per
table spec) - Figure files copied to metaPath as-is
Every time write_doc() (or save_report())
runs, it writes intermediate files to metaPath:
{hash}.json — The main spec file:
document structure, column definitions, styles, titles, footnotes,
headers/footers. This is what the C++ renderer reads.{dataRef}.json — One data file per
table spec, containing the actual row data.metaPath._index.json — An index of all spec
files written to this folder (auto-maintained).For most workflows, metaPath = tempdir() is fine — you
only care about the final .docx. But there are real reasons
to use a persistent metaPath.
Reproducibility / audit trail: In regulated environments (FDA, EMA submissions), you may need to prove that a specific DOCX was generated from a specific dataset at a specific time. The spec JSON + data JSON together form a complete, reproducible snapshot.
Re-rendering without R: Once the JSON files exist, you can re-render the DOCX without any R objects or data frames — just the JSON files. This is useful for: - Regenerating a document after a template change - Rendering on a different machine or in a CI/CD pipeline - Reproducing an output months later
Version management: Each write_doc()
call writes a new hash-named spec file. You can keep multiple versions
and compare them.
meta_dir <- "./meta"
# List all spec JSONs in the meta folder
df <- list_reports(meta_dir)
print(df[df$is_latest, c("doc_file", "datetime", "spec_file")])
# Re-render a DOCX from stored JSON (no R objects needed)
replay_report("demographics.docx", meta_dir = meta_dir)
# Or replay a specific version by spec hash
replay_report("abc123def456.json", meta_dir = meta_dir,
output_path = "./output/demographics_v2.docx")
# Clean up obsolete spec files (keeps latest version per document)
clean_reports(meta_dir, dry_run = TRUE) # Preview what would be deleted
clean_reports(meta_dir, dry_run = FALSE) # Actually deletelist_reports() returns a data frame
with columns: doc_file, datetime,
is_latest, n_specs, spec_file,
data_refs.
replay_report() re-renders from JSON —
no R spec objects, no data frames required. Pass either the target
.docx name (re-renders the latest version) or the exact
spec hash filename.
clean_reports() removes obsolete JSON
files. By default keeps 1 version per document
(keep_versions = 1). Always run with
dry_run = TRUE first.
# Set persistent meta directory once per session
tfl_set_options(
output_directory = "./output",
meta_directory = "./meta" # Persistent — survives session restarts
)
# All write_doc() calls now use these directories automatically
write_doc(report1, name = "tbl_demographics")
write_doc(report2, name = "tbl_labs")
# Later: re-render without R if needed
replay_report("tbl_demographics.docx", meta_dir = "./meta")When you create a table, widths are auto-calculated based on data characteristics:
# Auto-calculated widths (example)
# id = 20%, description = 50%, value = 30%
spec <- create_table(my_data)
# Lock id to 15%; others recalculate to fill 85%
spec <- define_cols(spec, id, colWidth = "15%")See Reporting Examples for detailed width customization.
Each table spec gets a dataRef name for its data
file:
# Auto-generated: "0001_abc123def456" (docOrder + hash)
report <- create_report(spec_table1, spec_table2)
# Manual control not needed — handled automatically by write_doc()
write_doc(report, name = "my_report", outDir = "./output", metaPath = "./meta")tfl_optionsSet defaults once, inherited by all new specs:
# Set session defaults
tfl_set_options(
add_header("Study ABC", "Locked Database", "CONFIDENTIAL"),
add_footer("Company Name", "Page {PAGE}", "2025"),
add_body_text("Analysis performed in R with ksTFL."))
# All new specs created afterward inherit these settings
spec1 <- create_table(data1) # Automatically gets headers/footers/body text
spec2 <- create_table(data2) # Also inherits defaults
# Check current options
tfl_get_options()
# Reset to package defaults
tfl_reset_options()library(ksTFL)
# --- Setup ---
data <- data.frame(
subject = sprintf("S%03d", 1:10),
age = round(rnorm(10, 45, 10)),
sex = sample(c("M", "F"), 10, TRUE)
)
# --- Create & customize ---
spec <- create_table(data, cols = c(subject, age, sex))
spec <- add_style(spec, id = "header",
s_font(bold = TRUE, font_size = "11pt"),
s_paragraph(alignment = "center"),
s_table_style(background_color = "#DDDDDD"))
spec <- define_cols(spec, c(subject, age, sex),
label = c("Subject ID", "Age (years)", "Sex"),
labelStyleRef = "header")
spec <- define_cols(spec, age, type = "numeric", format = "%.0f")
spec <- add_title(spec, "Demographics Table")
spec <- add_subtitle(spec, "All subjects in safety population")
spec <- add_footnote(spec, "Data are shown as observed.")
spec <- add_span_header(spec, c(age, sex), 'Characteristic',
labelStyleRef = "header", stubOrder = 1)
spec <- add_span_header(spec, c(subject, age, sex), 'Treatment A (N=10)',
labelStyleRef = "header", stubOrder = 2)
spec <- set_document(spec, contentWidth = '40%')
# --- Export ---
report <- create_report(spec) |> write_doc('demographics')
# Done!| Gotcha | Solution |
|---|---|
| Calling s_* helpers outside add_style() | Always use s_* inside add_style() — they validate
context |
| define_cols() with mismatched parameter lengths | Length must be 1 (recycled) or match number of columns |
| Styles from f_combine() not consolidated | Call create_report() before
write_doc() |
| Multiple add_header() calls stack | Each call appends a new header level; use
level = to replace a specific level |
| Figure file not found | Check path is absolute or relative to current working directory |
| create_text() does not accept data | create_text() takes no arguments — add content via
add_body_text() |
| Overlapping stubs at same stubOrder | Error; use different stubOrder or non-overlapping
column sets |
ksTFL ships with five RStudio Addins (available from the Addins drop-down in the RStudio toolbar). They provide interactive shortcuts for tasks that would otherwise require remembering function names or switching to the console.
Launches a Shiny application for creating and editing style templates
interactively. You can load any bundled template from
tfl_list_templates(), modify fonts, borders, spacing, and
colours in a WYSIWYG editor, then download the result as a JSON file
ready for use with set_page_style() or
write_doc(). This is especially useful when you need to
fine-tune a template visually rather than writing s_font()
/ s_paragraph() / s_table_style() calls by
hand.
Requires the shiny package.
Opens a Shiny application for selecting, reordering, and combining
previously saved reports into a single DOCX document. You point the app
at one or more meta-data folders (produced by save_report()
or write_doc()), drag-and-drop reports into the desired
order, optionally enable a table of contents, and render the combined
output — all without writing any R code.
Requires shiny, sortable, and
shinyFiles packages.
Evaluates the currently selected code in the source editor and, if
the result is a TFL_spec, renders an HTML preview in the
RStudio Viewer pane. This lets you highlight a pipeline expression
(e.g., create_table(...) |> add_title(...)) and
instantly see what the spec looks like — a quick visual check without
saving or rendering to DOCX.
Same HTML preview, but instead of evaluating selected text the addin
prompts you for the name of a TFL_spec object that already
exists in .GlobalEnv. Handy when the spec was built
interactively in the console and you want to preview it without
re-selecting code.
Prints all built-in style atoms to the console with colour-coded
categories (font decoration, font family, font size, text colour,
highlight, alignment, indentation, spacing, borders, backgrounds, row
height, and more). Each atom is a short name you can reference directly
in add_style() or define_cols() via
f_combine(). Running this catalog helps you discover what
is available without consulting documentation.
You now understand ksTFL’s core workflow. Next steps:
?create_table,
?define_cols, ?add_style,
?write_doc, ?list_reports?ksTFL (package
overview) or ?create_table, ?define_cols,
etc.| Task | Function | Notes |
|---|---|---|
| Create table spec | create_table(data, cols = ...) |
Auto-detects columns, types, widths |
| Create figure spec | create_figure(plot_or_path, dpi = 300L) |
File path or ggplot2 object; path must be readable |
| Create text spec | create_text() |
For narrative content only |
| Set document properties | set_document(spec, hasData = ...) |
Optional: configure content width, placement |
| Customize columns | define_cols(spec, cols, ...) |
Use c() for multiple columns |
| Define styles | add_style(spec, id = "name", ...) |
Use s_font(), s_paragraph(),
s_table_style() |
| Add spanning header | add_span_header(spec, cols, label, ...) |
Supports tidyselect; multi-level headers |
| Add titles/content | add_title(), add_footnote(),
add_body_text() |
Layer document content |
| Add page headers/footers | add_header(), add_footer() |
3 parts: left/center/right |
| Conditional row actions | compute_cols(spec, cond, ...) |
Use c_style(), c_merge(),
c_addrow(), c_glue(), c_clear(),
c_pageBreak() |
| Set page style | set_page_style(spec, page = p_page(...)) |
Configure page size, orientation, margins |
| Page settings helper | p_page(size, orientation, margins) |
"A4" / "Letter" / "Legal",
margins via p_margins() |
| List templates | tfl_list_templates() |
Shows all bundled template names |
| Discover style atoms | tfl_print_style_atoms() |
Prints all built-in style atoms grouped by category |
| Font status | tfl_font_status(), tfl_rescan_fonts() |
Check or re-run font discovery |
| Combine specs | create_report(spec1, spec2, ...) |
Consolidates styles, assigns order |
| Save + render (one step) | write_doc(report, name, ...) |
Recommended: saves JSON + renders DOCX |
| Save only | save_report(report, ...) |
Writes JSON + data files for manual rendering |
| Render from JSON | replay_report(spec_json, meta_dir, output_path, overrideTemplate = NULL) |
C++ renderer: JSON → styled DOCX |
| Set session defaults | tfl_set_options(...) |
Inherited by new specs in session |
| Check options | tfl_get_options(),
tfl_get_option(name) |
View current session settings |
| Reset options | tfl_reset_options() |
Back to package defaults |
tfl_options