--- title: "Styling Guide (ksTFL)" author: "ksTFL Team" output: rmarkdown::html_vignette: fig_width: 6 fig_height: 4 dev: pdf vignette: > %\VignetteIndexEntry{Styling Guide (ksTFL)} %\VignetteEncoding{UTF-8} %\VignetteEngine{knitr::rmarkdown} editor_options: markdown: wrap: 80 --- ```{r setup, include=FALSE} knitr::opts_chunk$set( comment = "", collapse = TRUE, eval = FALSE, dev = "png", dev.args = if (capabilities("cairo")) list(type = "cairo") else NULL ) options(pkgdown.internet = FALSE) ``` ksTFL logo ## Overview This guide covers the complete styling system in ksTFL: \- **Style primitives** (`s_*` helpers) for fonts, paragraphs, spacing, indentation, tables, and borders \- **Declaring named styles** with `add_style()` \- **Referencing and combining styles** with style references and `f_combine()` \- **Applying styles** to columns, labels, stubs, and content \- **Best practices** for maintainable, reusable style systems For runnable reporting examples integrating styles see [Reporting Examples](Reporting_Examples_with_ksTFL.html). For a quick start see [Getting Started](Getting_Started_with_ksTFL.html). ## Category and scope This is the reference vignette for readers building reusable style systems for teams or studies. The focus is style primitives, composition, references, and maintainable conventions. ------------------------------------------------------------------------ ## Styling philosophy and workflow ### Why declarative styles? Professional clinical documents require: - **Consistency**: common elements should render the same way everywhere. - **Maintainability**: one style change should update every reference. \- **Composability**: Build complex styles from simple building blocks (font + paragraph alignment + table background) \- **Separation of concerns**: Define styles once, apply them many times without repeating details ksTFL uses a **named style system**: you declare styles with `add_style()` giving each an `id`, then reference them by name where needed. Styles are composable (`f_combine()`) and consolidated automatically when you build reports. ### Best practices workflow 1. **Define atomic styles first**: Create small, focused styles (bold headers, right-aligned text, light gray background) 2. **Reference by name**: In `define_cols()`, `add_title()`, `add_span_header()` (with tidyselect support), use `labelStyleRef` or `valueStyleRef` to point to styles by id 3. **Combine when needed**: Use `f_combine()` to merge multiple styles on-the-fly for ad-hoc combinations 4. **Let `create_report()` consolidate**: The report builder automatically merges combined styles so the renderer receives clean, consolidated styles 5. **Never inspect internal fields**: Don't manually look at `spec$attribs$styles` — let the package manage consolidation ------------------------------------------------------------------------ ## Style primitives (s\_\* helpers) All style primitives begin with `s_` and must be used **only inside `add_style()`**. The helpers validate parameter names and values, raising informative errors if used incorrectly. ### `s_font()` — Font properties Control font appearance (name, size, weight, color, decorations). **Parameters**: \- `font_name`: Font family (e.g., "Arial", "Courier New", "Times New Roman", "Georgia") \- `font_size`: Size with units (e.g., "12pt", "11pt") - `bold`: Logical (TRUE/FALSE) \- `italic`: Logical (TRUE/FALSE) \- `underline`: Logical (TRUE/FALSE) \- `color`: Color as hex code (e.g., "#000000", "#FF0000") or color name (e.g., "red", "black", "blue") \- `highlight`: Background highlight color as hex code or color name **Example**: ```{r s_font_example, eval = FALSE} spec <- create_table(mtcars) # Bold, 12pt Arial, red text (using hex code) spec <- add_style(spec, id = "header_bold_red", s_font(font_name = "Arial", font_size = "12pt", bold = TRUE, color = "#CC0000")) # Underlined, 10pt monospace, blue text (using color name) spec <- add_style(spec, id = "code_style", s_font(font_name = "Courier New", font_size = "10pt", underline = TRUE, color = "blue")) # Yellow highlight with black text spec <- add_style(spec, id = "highlighted", s_font(color = "black", highlight = "yellow")) ``` ### `s_paragraph()` — Paragraph properties Control text alignment, spacing before/after, line spacing, and indentation. **Parameters**: \- `alignment`: Text alignment — "left", "right", "center", "justify", "distributed" \- `spacing`: Spacing before/after (use `s_spacing(...)`) \- `indents`: Left/right indentation, first-line indent (use `s_indents(...)`) **Example**: ```{r s_paragraph_example, eval = FALSE} spec <- create_table(mtcars) # Centered text with 6pt spacing before/after spec <- add_style(spec, id = "centered_spaced", s_paragraph(alignment = "center", spacing = s_spacing(before = "6pt", after = "6pt"))) # Right-aligned with left indent spec <- add_style(spec, id = "right_indented", s_paragraph(alignment = "right", indents = s_indents(left = "10pt"))) ``` ### `s_spacing()` — Line and paragraph spacing Controls spacing **before** a paragraph, **after** a paragraph, and **between lines**. **Parameters**: \- `before`: Space before paragraph (e.g., "6pt", "12pt") \- `after`: Space after paragraph (e.g., "6pt", "12pt") \- `line_spacing`: Line spacing multiplier (e.g., 1.0, 1.5, 2.0 for single/1.5-line/double spacing) **Note**: `s_spacing()` is always used **inside `s_paragraph()`**, never standalone. **Example**: ```{r s_spacing_example, eval = FALSE} spec <- create_table(mtcars) # Double-spaced with 12pt spacing after each paragraph spec <- add_style(spec, id = "double_spaced", s_paragraph(spacing = s_spacing(after = "12pt", line_spacing = 2.0))) ``` ### `s_indents()` — Indentation Controls left/right margins and first-line indentation within a paragraph. **Parameters**: \- `left`: Left indent (e.g., "10pt", "1cm") \- `right`: Right indent (e.g., "10pt") \- `first_line`: First-line indent (e.g., "20pt" for hanging indent) **Note**: `s_indents()` is always used **inside `s_paragraph()`**, never standalone. **Example**: ```{r s_indents_example, eval = FALSE} spec <- create_table(mtcars) # Hanging indent (first line outdented, rest indented) spec <- add_style(spec, id = "hanging_indent", s_paragraph(indents = s_indents(left = "20pt", first_line = "-20pt"))) # Left and right margins with left indent spec <- add_style(spec, id = "block_indent", s_paragraph(indents = s_indents(left = "30pt", right = "30pt"))) ``` ### `s_table_style()` — Table cell properties Control cell background, row height, vertical alignment, text orientation, and borders. **Parameters**: \- `background_color`: Cell background color (hex, e.g., "#E8E8E8") \- `row_height`: Height of table row (e.g., "25pt") \- `topEmptyLine`: Optional empty spacer row after header (e.g., "6pt", use `NULL` or `0pt` to disable) \- `bottomEmptyLine`: Optional empty spacer row before the bottom border (e.g., "6pt", use `NULL` or `0pt` to disable) \- `vertical_alignment`: "top", "center", "bottom" \- `text_orientation`: "horizontal", "vertical_90", "vertical_270" \- `borders`: Border specification (use `s_borders(...)`) **Example**: ```{r s_table_style_example, eval = FALSE} spec <- create_table(mtcars) # Light gray background, centered vertically, fixed row height spec <- add_style(spec, id = "header_cell", s_table_style(background_color = "#F2F2F2", row_height = "30pt", vertical_alignment = "center")) # Vertically rotated text (90 degrees) spec <- add_style(spec, id = "rotated_header", s_table_style(text_orientation = "vertical_90")) # Add table-level spacer rows via set_document() spec <- set_document( spec, topEmptyLine = "6pt", bottomEmptyLine = "6pt" ) ``` ### `s_borders()` — Border specifications Define borders for all four sides of a cell. Each side takes `s_border()` with line style, width, and color. **Parameters** (each side): \- `top`: Top border (use `s_border(...)`) \- `bottom`: Bottom border (use `s_border(...)`) \- `left`: Left border (use `s_border(...)`) \- `right`: Right border (use `s_border(...)`) **Note**: `s_borders()` can be used **inside `s_table_style()`** for cell-level borders, or **inside `s_paragraph()`** for paragraph-level borders. ### `s_border()` — Individual border line Defines a single border line with style, width, and color. **Parameters**: \- `color`: Color as hex code (e.g., "#000000") or color name (e.g., "black", "red") \- `width`: Line width (e.g., "1pt", "2pt", "0.5pt") \- `line_style`: "single", "double", "dashed", "dotted", "thick", "none" **Example**: ```{r s_borders_example, eval = FALSE} spec <- create_table(mtcars) # All borders: thin single lines in dark gray spec <- add_style(spec, id = "all_borders", s_table_style( borders = s_borders( top = s_border(color = "grey40", width = "1pt", line_style = "single"), bottom = s_border(color = "grey40", width = "1pt", line_style = "single"), left = s_border(color = "grey40", width = "1pt", line_style = "single"), right = s_border(color = "grey40", width = "1pt", line_style = "single") ) ) ) # Heavy bottom border in dark color (using hex code) spec <- add_style(spec, id = "bottom_border_heavy", s_table_style( borders = s_borders( bottom = s_border(color = "#333333", width = "2pt", line_style = "thick") ) ) ) ``` ### Paragraph-level borders MS Word distinguishes between cell borders (``) and paragraph borders (``). Cell borders always span the full cell width, while paragraph borders follow the text within the cell. This is particularly useful for spanning headers where a cell border would stretch across all merged columns, but a paragraph border only underlines the header label. Paragraph borders are set via `s_borders()` inside `s_paragraph()`: ```{r para_borders_example, eval = FALSE} spec <- create_table(my_data) # Paragraph bottom border — underlines only the text, not the full cell spec <- add_style(spec, id = "span_underline", s_font(bold = TRUE), s_paragraph( alignment = "center", borders = s_borders( bottom = s_border(color = "#000000", width = "0.5pt", line_style = "single") ) ) ) # Apply to a spanning header spec <- add_span_header(spec, cols = c("trt_a", "trt_b"), label = "Treatment Arms", labelStyleRef = "span_underline" ) # Combine paragraph border atom with other styles spec <- add_span_header(spec, cols = c("age", "sex"), label = "Demographics", labelStyleRef = f_combine("b", "ac", "pb_th") ) ``` **Key difference**: structural borders (`header_top_border`, `header_bottom_border`) override cell-level borders on header rows but cannot affect paragraph borders. This makes paragraph borders useful when you need visual separators independent of the table's structural framing. ------------------------------------------------------------------------ ## Declaring named styles with `add_style()` Named styles are the foundation of the ksTFL styling system. Each style has a unique `id` and contains one or more style primitives. ### Basic syntax ```{r add_style_basic, eval = FALSE} spec <- add_style(spec, id = "style_name", s_font(...), s_paragraph(...), s_table_style(...) ) ``` **Parameters**: \- `spec`: A `TFL_spec` object \- `id`: Unique name for the style (e.g., "header_bold", "numeric_right") \- `...`: One or more style primitives (`s_font()`, `s_paragraph()`, `s_table_style()`, etc.) ### Example: Define a complete style ```{r add_style_complete, eval = FALSE} spec <- create_table(mtcars) # Comprehensive header style: bold white text on gray background, centered spec <- add_style(spec, id = "table_header", s_font(font_name = "Arial", font_size = "12pt", bold = TRUE, color = "#FFFFFF"), s_paragraph(alignment = "center", spacing = s_spacing(before = "6pt", after = "6pt")), s_table_style(background_color = "#333333", row_height = "30pt", vertical_alignment = "center") ) # Simple numeric style: right-aligned spec <- add_style(spec, id = "numeric_right", s_paragraph(alignment = "right") ) # ID/key style: bold spec <- add_style(spec, id = "id_bold", s_font(bold = TRUE) ) ``` ### Multiple calls merge with last-win strategy Calling `add_style()` multiple times with the same `id` merges the styles (last-win semantics): ```{r add_style_merge, eval = FALSE} spec <- create_table(mtcars) # First call: defines font spec <- add_style(spec, id = "emphasis", s_font(bold = TRUE)) # Second call: adds paragraph alignment; bold is preserved spec <- add_style(spec, id = "emphasis", s_paragraph(alignment = "center")) # Result: "emphasis" has both bold font AND center alignment ``` ------------------------------------------------------------------------ ## Referencing and applying styles Once you declare styles with `add_style()`, reference them by id in various places: ### 1. Column labels — `labelStyleRef` in `define_cols()` Apply styles to **column header labels**: ```{r apply_label_style, eval = FALSE} spec <- create_table(mtcars) spec <- add_style(spec, id = "header_bold", s_font(bold = TRUE, font_size = "12pt")) # Apply to single column spec <- define_cols(spec, mpg, label = "MPG (miles/gallon)", labelStyleRef = "header_bold") # Apply to multiple columns with recycling spec <- define_cols(spec, c(hp, cyl), label = c("HP", "Cylinders"), labelStyleRef = "header_bold") # Different styles for different columns spec <- define_cols(spec, c(mpg, hp), label = c("MPG", "HP"), labelStyleRef = c("header_bold", "header_italic")) ``` ### 2. Column values — `valueStyleRef` in `define_cols()` Apply styles to **data values** in a column: ```{r apply_value_style, eval = FALSE} spec <- create_table(mtcars) spec <- add_style(spec, id = "numeric_right", s_paragraph(alignment = "right")) # Right-align all numeric values in the mpg column spec <- define_cols(spec, mpg, type = "numeric", valueStyleRef = "numeric_right") ``` ### 3. Spanning headers — `labelStyleRef` in `add_span_header()` Apply styles to **stub (spanning header) labels**: ```{r apply_stub_style, eval = FALSE} spec <- create_table(mtcars) spec <- add_style(spec, id = "stub_label", s_font(bold = TRUE, font_size = "11pt"), s_table_style(background_color = "#EFEFEF")) spec <- add_span_header(spec, cols = c("mpg", "cyl"), label = "Engine", labelStyleRef = "stub_label") ``` ### 4. Content — `styleRef` in `add_title()`, `add_footnote()` Apply styles to titles, subtitles, footnotes: ```{r apply_content_style, eval = FALSE} spec <- create_table(mtcars) spec <- add_style(spec, id = "title_style", s_font(bold = TRUE, font_size = "14pt"), s_paragraph(alignment = "center")) spec <- add_title(spec, "Motor Trends Analysis", styleRef = "title_style") ``` ------------------------------------------------------------------------ ## Combining styles with `f_combine()` `f_combine()` lets you apply multiple styles to a single element without pre-defining a combined style. ### Basic usage ```{r f_combine_basic, eval = FALSE} spec <- create_table(mtcars) spec <- add_style(spec, id = "bold", s_font(bold = TRUE)) spec <- add_style(spec, id = "red", s_font(color = "red")) # Using color name spec <- add_style(spec, id = "centered", s_paragraph(alignment = "center")) # Apply bold + red + centered to a column header spec <- define_cols(spec, mpg, label = "MPG", labelStyleRef = f_combine("bold", "red", "centered")) ``` ### When to use `f_combine()` vs named styles | Use Case | Approach | | -------------------------------------------- | ------------------------------------------------------- | | **Reusable style** (used in 3+ places) | Define a named style with `add_style()` | | **One-off combination** (used once or twice) | Use `f_combine()` inline | | **Complex style** (many properties) | Define named style, then optionally combine with others | | **Per-column variations** | Use `f_combine()` with per-column vectors | ### Combining with per-column mapping Apply different combinations to different columns: ```{r f_combine_per_column, eval = FALSE} spec <- create_table(mtcars) # Define base styles spec <- add_style(spec, id = "bold", s_font(bold = TRUE)) spec <- add_style(spec, id = "italic", s_font(italic = TRUE)) spec <- add_style(spec, id = "centered", s_paragraph(alignment = "center")) spec <- add_style(spec, id = "right", s_paragraph(alignment = "right")) # Apply different combinations per column spec <- define_cols(spec, c(mpg, cyl, hp), label = c("MPG", "Cylinders", "HP"), labelStyleRef = c( f_combine("bold", "centered"), # mpg: bold + centered f_combine("italic", "right"), # cyl: italic + right f_combine("bold", "italic", "centered") # hp: bold + italic + centered ) ) ``` ------------------------------------------------------------------------ ## Allowed values (enumerations) ### Color names Color parameters accept both **hex codes** (e.g., `"#FF0000"`) and **named colors**: **Basic colors**: black, white, red, green, blue, yellow, orange, purple, pink, brown, cyan, magenta, navy, teal, lime, maroon, olive, silver, gold, coral, salmon, turquoise, violet, indigo, khaki, lavender, plum, tan **Grayscale**: grey10, grey20, grey30, grey40, grey60, grey70, grey80, grey90 (or gray with 'a') ### Font names (common) - Arial - Courier New - Times New Roman - Georgia - Verdana - Trebuchet MS ### Alignment - "left" - "right" - "center" - "justify" - "distributed" ### Border line styles - "single" (solid line) - "double" (two lines) - "dashed" (dashed line) - "dotted" (dotted line) - "thick" (thicker solid line) - "none" (no border) ### Vertical alignment - "top" - "center" - "bottom" ### Text orientation - "horizontal" (default) - "vertical_90" (rotated 90° counter-clockwise) - "vertical_270" (rotated 270° counter-clockwise) ------------------------------------------------------------------------ ## Common styling patterns ### Pattern 1: Clinical table headers ```{r pattern_clinical_header, eval = FALSE} spec <- create_table(my_data) spec <- add_style(spec, id = "clinical_header", s_font(font_name = "Arial", font_size = "11pt", bold = TRUE, color = "#FFFFFF"), s_paragraph(alignment = "center"), s_table_style(background_color = "#003366", row_height = "28pt", vertical_alignment = "center") ) spec <- define_cols(spec, c("col1", "col2", "col3"), labelStyleRef = "clinical_header") ``` ### Pattern 2: Right-aligned numeric columns ```{r pattern_numeric, eval = FALSE} spec <- add_style(spec, id = "numeric_format", s_font(font_name = "Courier New", font_size = "10pt"), s_paragraph(alignment = "right") ) spec <- define_cols(spec, c(age, weight, dose), type = "numeric", valueStyleRef = "numeric_format") ``` ### Pattern 3: ID/key columns (bold, wide) ```{r pattern_id_column, eval = FALSE} spec <- add_style(spec, id = "id_column", s_font(bold = TRUE, font_size = "11pt"), s_paragraph(alignment = "left") ) spec <- define_cols(spec, subject_id, label = "Subject ID", labelStyleRef = "id_column", colWidth = "15%", isID = TRUE) ``` ### Pattern 4: Multi-level headers with styled stubs ```{r pattern_multi_stub, eval = FALSE} spec <- add_style(spec, id = "level1_stub", s_font(bold = TRUE, font_size = "12pt", color = "#FFFFFF"), s_table_style(background_color = "#666666", vertical_alignment = "center")) spec <- add_style(spec, id = "level2_stub", s_font(bold = TRUE, font_size = "11pt"), s_table_style(background_color = "#CCCCCC", vertical_alignment = "center")) spec <- add_span_header(spec, cols = c("var1", "var2", "var3"), label = "Baseline", stubOrder = 1, labelStyleRef = "level1_stub") spec <- add_span_header(spec, cols = c("var1", "var2"), label = "Safety", stubOrder = 2, labelStyleRef = "level2_stub") ``` ------------------------------------------------------------------------ ## Troubleshooting ### Error: "Context error" or "can only be used inside add_style()" **Problem**: You used an `s_*` helper outside `add_style()`. ```{r error_context, eval = FALSE} # WRONG my_style <- s_font(bold = TRUE) # ERROR # CORRECT spec <- add_style(spec, id = "my_style", s_font(bold = TRUE)) ``` ### Error: "Invalid parameter" or "Allowed values are..." **Problem**: You used an invalid parameter value (e.g., "bolded" instead of TRUE). ```{r error_invalid, eval = FALSE} # WRONG s_font(bold = "bolded") # ERROR: must be TRUE/FALSE # CORRECT s_font(bold = TRUE) ``` ### Styles not applied after `create_report()` **Problem**: If you used `f_combine()`, you must call `create_report()` before the styles are consolidated. ```{r error_consolidate, eval = FALSE} spec <- create_table(mtcars) spec <- define_cols(spec, mpg, labelStyleRef = f_combine("bold", "red")) # CORRECT: create_report() consolidates combined styles before rendering report <- create_report(spec) # Merges "bold" + "red" into a single resolved style write_doc(report, name = "out", outDir = "./output", metaPath = tempdir()) ``` ### Styles looking different in renderer than expected **Problem**: Renderer may override or ignore certain style properties based on its own template system. **Solution**: Test with simple styles first, then incrementally add properties. Contact your renderer maintainer for constraints. ------------------------------------------------------------------------ ## Advanced notes ### Style consolidation in `create_report()` When you call `create_report()`, the package: 1\. Collects all specs 2\. For each spec, finds all style references used with `f_combine()` 3\. Merges those combined styles into single consolidated styles 4\. Generates unique hash-based names for consolidated styles 5\. Updates all references to point to the consolidated style You don't need to inspect or manipulate `spec$attribs$styles` — the consolidation is automatic and transparent. ### Style reference resolution Style references are resolved in this order: 1\. **Named styles** defined in the same spec with `add_style()` 2\. **Built-in style atoms** shipped with the package (e.g., `"b"`, `"tw_80"`, `"grp_hdr"`) 3\. **Error**: If reference not found, `create_report()` will error with an informative message ------------------------------------------------------------------------ ## Built-in style atoms ksTFL ships a library of single-property style atoms accessible via `f_combine()` or directly as `styleRef` values. Each atom sets exactly one visual property; compose them freely with `f_combine()`. **Discovering atoms programmatically**: Use `tfl_print_style_atoms()` (or its alias `tfl_style_atoms_catalog()`) to print all available atoms grouped by category with colour-coded output in the console: ```{r discover_atoms, eval = FALSE} # Print all built-in atoms categorised and colour-coded tfl_print_style_atoms() ``` ### Complete atom reference | Atom | Effect | | ------------------------------------------------------------------ | ------------------------------------------------------------------------- | | **Font — decoration** | | | `b` / `font_bold` | Bold | | `i` / `font_italic` | Italic | | `u` / `font_underline` | Underline | | **Font — family** | | | `font_arial` | Set `font_name = "Arial"` | | `font_courier_new` | Set `font_name = "Courier New"` | | `font_times_new_roman` | Set `font_name = "Times New Roman"` | | `font_georgia` | Set `font_name = "Georgia"` | | `font_verdana` | Set `font_name = "Verdana"` | | `font_trebuchet_ms` | Set `font_name = "Trebuchet MS"` | | **Font — size** | | | `fs_7` … `fs_11` | Font size 7 pt … 11 pt | | **Font — colour** | | | `fc_black`, `fc_red`, `fc_blue`, `fc_green` | Pure text colours | | `fc_gray` / `fc_grey` | Secondary / reference text (#595959) | | `fc_navy`, `fc_teal`, `fc_olive`, `fc_rust`, `fc_plum`, `fc_slate` | Muted clinical palette | | **Text highlight (cell shading)** | | | `hl_yellow`, `hl_red`, `hl_green`, `hl_gray` / `hl_grey` | Strong highlight colours | | `hl_peach`, `hl_mint`, `hl_sky`, `hl_lemon`, `hl_lilac` | Pastel highlight palette | | **Paragraph — alignment** | | | `al` / `text_left` | Left-align | | `ar` / `text_right` | Right-align | | `ac` / `text_center` | Center-align | | **Paragraph — left indentation** | | | `ind0` / `indent_0` | No indent (reset to left margin) | | `ind1` / `indent_1` | 0.5 cm left indent (top-level category) | | `ind2` / `indent_2` | 1.0 cm left indent (first sub-group) | | `ind3` / `indent_3` | 1.5 cm left indent (second sub-group) | | `ind4` / `indent_4` | 2.0 cm left indent (detail) | | **Paragraph — right indentation** | | | `rind0` / `rindent_0` | No right indent (reset to right margin) | | `rind1` / `rindent_1` | 0.5 cm right indent | | `rind2` / `rindent_2` | 1.0 cm right indent | | `rind3` / `rindent_3` | 1.5 cm right indent | | `rind4` / `rindent_4` | 2.0 cm right indent | | **Paragraph — table-width shrink** | | | `tw_95` … `tw_50` | Symmetric left+right indent to match table at 95 %…50 % width (5 % steps) | | **Paragraph — spacing** | | | `sp_0` | No space before/after paragraph | | `sp_2` | 2 pt space before and after | | `sp_4` | 4 pt space before and after | | **Paragraph — pagination** | | | `kl` | Keep all lines of a cell on the same page | | `kn` | Keep this row on the same page as the next row | | **Group / category header composites** | | | `grp_hdr` | Bold + 4 pt space above + left indent reset (category header) | | `grp_hdr_i` | Bold + italic + 4 pt space above + left indent reset | | **Cell — vertical alignment** | | | `va_t` / `va_top` | Top | | `va_m` / `va_center` | Middle | | `va_b` / `va_bottom` | Bottom | | **Cell — text orientation** | | | `to_h` / `text_horizontal` | Horizontal (default) | | `to_90` / `text_vertical_90` | Rotated 90° (bottom-to-top) | | `to_270` / `text_vertical_270` | Rotated 270° (top-to-bottom) | | **Cell — background colour** | | | `bg_blue`, `bg_gray` / `bg_grey` | Standard backgrounds | | `bg_peach`, `bg_mint`, `bg_sky`, `bg_lemon`, `bg_lilac` | Pastel backgrounds | | `bg_navy`, `bg_slate`, `bg_steel` | Dark/medium header backgrounds | | **Row height** | | | `row_h2`, `row_h4`, `row_h6` | Row height 2 / 4 / 6 pt (separator rows) | | **Border — sides (1 pt black)** | | | `bt`, `bb`, `bl`, `br` | Top / bottom / left / right border | | **Border — thin sides (0.5 pt black)** | | | `bt_th`, `bb_th` | Thin top / bottom border | | **Border — colour override** | | | `bc_gray` / `bc_grey` | All sides → medium gray (#AAAAAA) | | `bc_white` | All sides → white / none (suppress borders) | | **Border — thick white sides (column separation)** | | | `brw_thick` | Right border 4 pt white (visual column gap) | | `blw_thick` | Left border 4 pt white (visual column gap) | | **Paragraph border — bottom** | | | `pb` | Paragraph bottom border 1 pt black | | `pb_th` | Paragraph bottom border 0.5 pt black (thin) | **Usage:** ```{r atoms_usage, eval = FALSE} # Single atom as styleRef spec <- add_footnote(spec, "Source: database.", styleRef = "tw_80") # Combine atoms with f_combine() spec <- define_cols(spec, value, valueStyleRef = f_combine("font_verdana", "ar", "fs_9")) # Combine atoms with named styles spec <- add_style(spec, id = "group_hdr", s_font(bold = TRUE), s_paragraph(spacing = s_spacing(before = "4pt"))) spec <- compute_cols(spec, firstOf(group), c_style(everything(), styleRef = f_combine("group_hdr", "bg_gray"))) ``` ### Table-width shrink atoms (`tw_*`) When a table is narrower than the full content width, titles, subtitles, footnotes, and body text will span the full page width by default — wider than the table itself. The `tw_*` atoms apply symmetric left and right paragraph indentation so that text blocks visually align with the table edges. Indent values are calculated for **A4 landscape with 0.5 in left/right page margins** (content width ≈ 27.16 cm). Each 5 % step corresponds to 0.68 cm per side. | Atom | Table width | Indent each side | | ------- | ----------- | ---------------- | | `tw_95` | 95 % | 0.68 cm | | `tw_90` | 90 % | 1.36 cm | | `tw_85` | 85 % | 2.04 cm | | `tw_80` | 80 % | 2.72 cm | | `tw_75` | 75 % | 3.40 cm | | `tw_70` | 70 % | 4.07 cm | | `tw_65` | 65 % | 4.75 cm | | `tw_60` | 60 % | 5.43 cm | | `tw_55` | 55 % | 6.11 cm | | `tw_50` | 50 % | 6.79 cm | **Usage — match footnotes and titles to a narrower table:** ```{r tw_basic, eval = FALSE} spec <- create_table(data) |> set_document(contentWidth = "80%") |> add_title("Demographics Table", styleRef = "tw_80") |> add_subtitle("Safety Population", styleRef = "tw_80") |> add_footnote("Source: study database.", styleRef = "tw_80") ``` **Combine with other atoms** using `f_combine()`: ```{r tw_combine, eval = FALSE} # Bold title, indented to match a 75 % table spec <- add_title(spec, "Efficacy Summary", styleRef = f_combine("b", "tw_75")) # Small italic footnote, indented to match a 70 % table spec <- add_footnote(spec, "Values are least-squares means.", styleRef = f_combine("i", "fs_8", "tw_70")) ``` **Apply via a named style** for reuse across multiple specs: ```{r tw_named, eval = FALSE} # Define the style on each spec (or use a helper function to apply it) add_footnote_80 <- function(spec, text) { spec <- add_style(spec, id = "fn_80", s_font(font_size = "8pt", italic = TRUE), s_paragraph(alignment = "left", indents = s_indents(left = "2.72cm", right = "2.72cm"))) add_footnote(spec, text, styleRef = "fn_80") } spec1 <- add_footnote_80(spec1, "a. p < 0.05") spec2 <- add_footnote_80(spec2, "b. LOCF imputation") ``` > **Note**: The indent values assume the default A4 landscape page with > 0.5 in margins. If you use a different page size, orientation, or > margins via `set_page_style()`, calculate your own indents with > `s_indents(left = ..., right = ...)` inside `add_style()`. ------------------------------------------------------------------------ ## See also - Function documentation: `?add_style`, `?s_font`, `?s_paragraph`, `?f_combine` - [Reporting Examples](Reporting_Examples_with_ksTFL.html) — working examples with styles - [Getting Started](Getting_Started_with_ksTFL.html) — quick overview