tabviz provides a layered styling system that lets you control appearance at multiple levels, from broad theme choices down to individual cell formatting.

Styling Layers

Styling in tabviz operates at four distinct levels, each building on the previous:

┌─────────────────────────────────────────────────────┐
│  Theme (base colors, fonts, spacing)                │
│  ┌───────────────────────────────────────────────┐  │
│  │  Row Styling (bold, color, background)        │  │
│  │  ┌─────────────────────────────────────────┐  │  │
│  │  │  Cell Styling (per-column formatting)   │  │  │
│  │  │  ┌───────────────────────────────────┐  │  │  │
│  │  │  │  Marker Styling (forest markers)  │  │  │  │
│  │  │  └───────────────────────────────────┘  │  │  │
│  │  └─────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘

1. Theme Level

Themes define the foundational look: colors, typography, spacing, and shapes. They affect the entire table.

Code
data(glp1_trials)
sample_data <- head(glp1_trials[glp1_trials$row_type == "data", ], 4)

# Theme controls overall appearance
tabviz(sample_data, label = "study",
  columns = list(
    col_text("drug", "Drug"),
    viz_forest(point = "hr", lower = "lower", upper = "upper",
               scale = "log", null_value = 1, width = 160),
    col_interval("HR (95% CI)", point = "hr", lower = "lower", upper = "upper")
  ),
  theme = web_theme_jama()  # Publication styling
)

2. Row Level

Row styling applies formatting to entire rows based on data conditions. This is useful for highlighting summary rows, significant results, or groupings.

Code
# Row styling for conditional formatting
tabviz(sample_data, label = "study",
  columns = list(
    col_text("drug", "Drug"),
    viz_forest(point = "hr", lower = "lower", upper = "upper",
               scale = "log", null_value = 1, width = 160),
    col_interval("HR (95% CI)", point = "hr", lower = "lower", upper = "upper")
  ),
  row_bold = ~ upper < 1,  # Bold significant results
  theme = web_theme_jama()
)

3. Cell Level

Cell styling targets individual columns, letting you format specific values differently.

Code
# Cell styling for specific columns
tabviz(sample_data, label = "study",
  columns = list(
    col_text("drug", "Drug"),
    viz_forest(point = "hr", lower = "lower", upper = "upper",
               scale = "log", null_value = 1, width = 160),
    col_numeric("hr", "HR", decimals = 2,
                bold = ~ .x < 1,  # Bold HR values < 1
                color = ~ ifelse(.x < 1, "#16a34a", "#64748b"))
  ),
  theme = web_theme_jama()
)

4. Marker Level

Marker styling controls the appearance of data points in forest plots: color, shape, size, and opacity.

Code
# Marker styling for forest plot points
tabviz(sample_data, label = "study",
  columns = list(
    col_text("drug", "Drug"),
    viz_forest(point = "hr", lower = "lower", upper = "upper",
               scale = "log", null_value = 1, width = 160),
    col_interval("HR (95% CI)", point = "hr", lower = "lower", upper = "upper")
  ),
  marker_color = ~ ifelse(upper < 1, "#16a34a", "#64748b"),  # Green if significant
  marker_shape = ~ ifelse(upper < 1, "diamond", "square"),
  theme = web_theme_jama()
)

Cascade and Precedence

More specific styling overrides more general styling:

  1. Theme defaults are the base
  2. Row styling overrides theme for affected rows
  3. Cell styling overrides row styling for specific cells
  4. Inline styles (via formula expressions) override everything

This means you can set a consistent base with themes, then add targeted overrides where needed.

Formula Expressions

tabviz uses R formula syntax (~ expression) for conditional styling. This is a concise way to apply styling based on data values.

Row and Marker Formulas

For row-level and marker styling, formulas can reference any column in your data:

# Reference any column by name
row_bold = ~ pvalue < 0.05
marker_color = ~ ifelse(group == "Treatment", "blue", "gray")
row_bg = ~ case_when(
  row_type == "summary" ~ "#f0f0f0",
  significant ~ "#e6ffe6",
  TRUE ~ "white"
)

Cell Formulas

For cell-level styling within column definitions, use .x to reference the column’s own values:

# .x refers to the current column's value
col_numeric("hr", "HR", bold = ~ .x < 1)
col_pvalue("pvalue", "P", color = ~ ifelse(.x < 0.05, "red", "black"))

Choosing the Right Level

Want to style… Use
Overall look and feel Theme (theme = web_theme_*())
Entire rows conditionally Row styling (row_bold, row_color, etc.)
Specific columns Cell styling (bold, color in col_*())
Forest plot markers Marker styling (marker_color, marker_shape, etc.)

Next Steps