Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/davidgohel/flextable/llms.txt

Use this file to discover all available pages before exploring further.

flextable provides two approaches for Word and PowerPoint output: convenience functions that create a new file directly, and officer integration functions for adding tables to existing documents.

Word output

Save to a new Word file

save_as_docx() creates a Word document containing one or more tables. Each table is placed on its own section separated by a blank paragraph. If the objects are named, the names are used as heading 2 titles above each table.
library(flextable)
library(officer)

ft1 <- flextable(head(iris))
ft2 <- flextable(head(mtcars))

tf <- tempfile(fileext = ".docx")
save_as_docx(`iris table` = ft1, `mtcars table` = ft2, path = tf)

Page layout with pr_section

Pass an officer::prop_section object to control page orientation, size, and margins:
library(officer)

sect_properties <- prop_section(
  page_size = page_size(
    orient = "landscape",
    width = 8.3, height = 11.7
  ),
  type = "continuous",
  page_margins = page_mar()
)

save_as_docx(
  `iris table` = ft1, `mtcars table` = ft2,
  path = tf, pr_section = sect_properties
)

RTF output

save_as_rtf() works identically to save_as_docx() but produces an RTF file. It also accepts a pr_section argument and supports page headers:
library(officer)

sect_properties <- prop_section(
  page_size = page_size(orient = "landscape", width = 8.3, height = 11.7),
  type = "continuous",
  page_margins = page_mar(),
  header_default = block_list(
    fpar(ftext("text for default page header")),
    qflextable(data.frame(a = 1L))
  )
)

tf <- tempfile(fileext = ".rtf")
save_as_rtf(
  `iris table` = ft1, `mtcars table` = ft2,
  path = tf, pr_section = sect_properties
)

Adding to an existing officer document

body_add_flextable()

Use body_add_flextable() to add a table to an rdocx object created with officer::read_docx(). This gives you full control over document construction:
library(officer)

set_flextable_defaults(
  split = TRUE,
  table_align = "center",
  table.layout = "autofit"
)

ft_1 <- flextable(head(airquality, n = 20))
ft_1 <- color(ft_1, i = ~ Temp > 70, color = "red", j = "Temp")
ft_1 <- set_caption(
  x = ft_1,
  autonum = run_autonum(seq_id = "tab"),
  caption = "Daily air quality measurements"
)
ft_1 <- paginate(ft_1, init = TRUE, hdr_ftr = TRUE)

ft_2 <- proc_freq(mtcars, "vs", "gear")
ft_2 <- set_caption(
  x = ft_2,
  autonum = run_autonum(seq_id = "tab", bkm = "mtcars"),
  caption = as_paragraph(
    as_b("mtcars"), " ",
    colorize("table", color = "orange")
  ),
  fp_p = fp_par(keep_with_next = TRUE)
)
ft_2 <- paginate(ft_2, init = TRUE, hdr_ftr = TRUE)

doc <- read_docx()
doc <- body_add_flextable(doc, value = ft_1)
doc <- body_add_par(doc, value = "")
doc <- body_add_flextable(doc, value = ft_2)

fileout <- tempfile(fileext = ".docx")
print(doc, target = fileout)
Parameters:
ParameterDescriptionDefault
xAn rdocx object
valueA flextable object
align"left", "center", or "right"NULL (inherits from table)
posCursor position: "after", "before", "on""after"
splitAllow row breaks across pagesNULL
topcaptionPlace caption above (TRUE) or below (FALSE) the tableTRUE
Prefer set_flextable_defaults(table_align = "center") and set_table_properties(opts_word = list(split = TRUE)) over the align and split arguments in body_add_flextable().

Replace content at a bookmark

body_replace_flextable_at_bkm() replaces a bookmarked paragraph in a Word document with a flextable. The bookmark is removed as a side effect:
doc <- read_docx("template.docx")  # template with a bookmark named "results_table"
doc <- body_replace_flextable_at_bkm(
  x = doc,
  bookmark = "results_table",
  value = ft
)
print(doc, target = "output.docx")

PowerPoint output

Save to a new PowerPoint file

save_as_pptx() creates a PowerPoint presentation with one table per slide. Named objects become slide titles:
ft1 <- flextable(head(iris))
ft2 <- flextable(head(mtcars))

tf <- tempfile(fileext = ".pptx")
save_as_pptx(`iris table` = ft1, `mtcars table` = ft2, path = tf)
PowerPoint ignores captions set with set_caption(). Captions are not supported in the PowerPoint format.

Add to an existing officer presentation

ph_with() is the officer generic for adding content to a placeholder. flextable provides the ph_with.flextable() method, which converts the table to a native PowerPoint table:
library(officer)

ft <- flextable(head(iris))

doc <- read_pptx()
doc <- add_slide(doc, "Title and Content", "Office Theme")
doc <- ph_with(doc, ft, location = ph_location_left())

fileout <- tempfile(fileext = ".pptx")
print(doc, target = fileout)
Use officer::ph_location_type() to target a specific placeholder type:
doc <- add_slide(doc, layout = "Title and Content", master = "Office Theme")
doc <- ph_with(doc, value = ft, location = ph_location_type(type = "body"))
Table width and height are determined by flextable cell dimensions, not by the placeholder location. Use width(), height(), autofit(), and dim_pretty() to control the table size before placing it.

PowerPoint limitations

  • PowerPoint only supports fixed table layout. Use autofit() to adjust column widths.
  • Images inside table cells are not supported in PowerPoint.
  • Row and column spans rendered from flextable may differ from native PowerPoint span behavior.

Pagination and page breaks

paginate() controls how table rows behave across page breaks in Word and RTF output. It applies the “keep with next” attribute to groups of rows so they stay together on a page.
library(flextable)

# Keep all rows together (small tables)
ft <- paginate(ft, init = TRUE, hdr_ftr = TRUE)

# Keep header with first body row only (large tables)
ft <- paginate(ft, init = FALSE, hdr_ftr = TRUE)

# Keep rows within groups together
ft <- paginate(ft, group = "cut", group_def = "rle")
The group_def argument controls how groups are identified:
ValueAlgorithm
"rle"Groups consecutive equal values in group column (use with tabulator())
"nonempty"A new group starts wherever group column is non-empty
"starts"group is an integer vector of row indices that begin new groups
paginate() only applies to Word and RTF output. It has no effect on HTML or PDF.

Clinical shift tables

shift_table() prepares a laboratory test results dataset in CDISC format for display as a shift table with tabulator(). A shift table shows how subjects move between reference range categories (Low/Normal/High) from baseline to follow-up visits.
library(flextable)

SHIFT_TABLE <- shift_table(
  x = labdata,
  cn_visit = "VISIT",
  cn_grade = "LBNRIND",
  cn_usubjid = "USUBJID",
  cn_lab_cat = "LBTEST",
  cn_treatment = "TREAT",
  cn_is_baseline = "LBBLFL",
  baseline_identifier = "Y",
  grade_levels = c("LOW", "NORMAL", "HIGH")
)

# Post-process with the attribute helpers
visit_as_factor <- attr(SHIFT_TABLE, "FUN_VISIT")
range_as_factor <- attr(SHIFT_TABLE, "FUN_GRADE")
SHIFT_TABLE$VISIT   <- visit_as_factor(SHIFT_TABLE$VISIT)
SHIFT_TABLE$LBNRIND <- range_as_factor(SHIFT_TABLE$LBNRIND)

# Use with tabulator()
tab <- tabulator(
  x = SHIFT_TABLE,
  hidden_data = attr(SHIFT_TABLE, "VISIT_N"),
  rows = c("LBTEST", "VISIT", "BASELINE"),
  columns = c("TREAT", "LBNRIND"),
  `n` = as_paragraph(N)
)
ft <- as_flextable(tab,
  separate_with = "VISIT",
  label_rows = c(LBTEST = "Lab Test", VISIT = "Visit", BASELINE = "Baseline Range")
)
ft
shift_table() returns the processed data frame with three attributes: VISIT_N (visit counts for use as hidden_data), FUN_VISIT (factor conversion for visit column), and FUN_GRADE (factor conversion adding MISSING/SUM levels).

Build docs developers (and LLMs) love