Get started

Published

March 13, 2025

Introduction

Tabset is an interactive panel in Quarto html documents.

Tab content for A

Tab content for B

This was written as follows.

::: {.panel-tabset}
## A

Tab content for A

## B

Tab content for B
:::

It would be tedious to manually rewrite this each time the number of tabs increases or decreases. The quartabs::render_tabset() takes a data frame as input and outputs it dynamically. Note that the chunk option must be results: asis.

```{r}
#| results: asis

data.frame(
  tab = c("A", "B"),
  value = c("Tab content for A", "Tab content for B")
) |>
  quartabs::render_tabset(tab, value)
```

Tab content for A

Tab content for B

Basic usage

Here are basic examples. First, load the libraries used in this demo and create sample data.

library(quartabs)
library(tibble)
library(dplyr)
library(purrr)
library(tidyr)
library(plotly)
library(htmltools)
library(knitr)
library(gt)
library(DT)
library(tinytable)
library(reactable)
library(flextable)

# sample data
df1 <- tibble(
  # id: intentionally created in descending order for the examples shown later
  id = paste0("id", 6:1),
  group1 = c(rep("A", 3), rep("B", 3)),
  group2 = rep(c("X", "Y", "Z"), 2),
  var1 = 1:6,
  var2 = list(1, 2, 3, 4, 5, 6),
  var3 = factor(letters[1:6])
)

df1
# A tibble: 6 × 6
  id    group1 group2  var1 var2      var3 
  <chr> <chr>  <chr>  <int> <list>    <fct>
1 id6   A      X          1 <dbl [1]> a    
2 id5   A      Y          2 <dbl [1]> b    
3 id4   A      Z          3 <dbl [1]> c    
4 id3   B      X          4 <dbl [1]> d    
5 id2   B      Y          5 <dbl [1]> e    
6 id1   B      Z          6 <dbl [1]> f    

tabset_vars, output_vars

The tabset_vars argument specifies columns to display as tab labels. The output_vars argument specifies the columns to display in the tab.

Don’t forget!

Make sure to set the chunk option to results: asis.

Default chunk options can be changed if necessary.

knitr::opts_chunk$set(
  results = "asis"
)
```{r}
#| results: asis

df1 |>
  render_tabset(id, var1)
```

6

5

4

3

2

1

The sort argument (defaults to TRUE) sorts the data by tabsest_vars. Therefore, the id column were displayed in ascending order.

If sort = FALSE, the tabset will be output in the original order of the data.

```{r}
#| results: asis

df1 |>
  render_tabset(id, var1, sort = FALSE)
```

1

2

3

4

5

6

Multiple tabset_vars and output_vars are acceptable. For multiple tabset_vars, they are displayed nested.

```{r}
#| results: asis

df1 |>
  render_tabset(c(group1, group2), c(var1, var2, var3))
```

1

[1] 1

a

2

[1] 2

b

3

[1] 3

c

4

[1] 4

d

5

[1] 5

e

6

[1] 6

f

cat() or print()

cat() is used internally for non-list columns to avoid unnecessary prefixes such as “[1]” in the output. On the other hand, print() is used for list columns.

For example, var1 displays “1”, while var2 of type list displays “[1] 1”.

Factor, Date and POSIXt displays

In render_tabset(), cat() is used to output for columns that are not list types. However, if cat() is used, factor, Date, POSIXt are output as an integer. So, if these are included in tabset_vars or output_vars, it is converted internally to string (after sorting if sort = TRUE).

Here are some simple examples. First, define test objects.

(test_factor <- factor("a"))
[1] a
Levels: a
(test_date <- as.Date("2025-01-01"))
[1] "2025-01-01"
(test_posixct <- as.POSIXct("2025-01-01 12:34:56", tz = "UTC"))
[1] "2025-01-01 12:34:56 UTC"

Using cat() results in output as a number. This is not usually the expected output.

cat(test_factor)
1
cat(test_date)
20089
cat(test_posixct)
1735734896

Therefore, render_tabset() uses cat() after converting it internally to a string as follows.

cat(as.character(test_factor))
a
cat(as.character(test_date))
2025-01-01
cat(as.character(test_posixct))
2025-01-01 12:34:56

layout

How can I display the content in a tabset horizontally? In Quarto, layout-ncol can be used.

```{r}
#| results: asis
#| layout-ncol: 3

df1 |>
  render_tabset(c(group1, group2), c(var1, var2, var3))
```

1

[1] 1

a

2

[1] 2

b

3

[1] 3

c

4

[1] 4

d

5

[1] 5

e

6

[1] 6

f

Oops, the entire tabset is now a third of the width. We want the content within to be displayed side by side without changing the width of the tabset. This is where the layout argument comes in handy.

```{r}
#| results: asis

df1 |>
  render_tabset(
    c(group1, group2),
    c(var1, var2, var3),
    layout = "::: {layout-ncol=3}"
  )
```

1

[1] 1

a

2

[1] 2

b

3

[1] 3

c

4

[1] 4

d

5

[1] 5

e

6

[1] 6

f

In fact, the above layout is a shortcut to something like this:

```{r}
#| results: asis

df1 |>
  mutate(
    layout_start = "::: {layout-ncol=3}",
    layout_end = ":::"
  ) |>
  render_tabset(
    c(group1, group2),
    c(layout_start, var1, var2, var3, layout_end)
  )
```

1

[1] 1

a

2

[1] 2

b

3

[1] 3

c

4

[1] 4

d

5

[1] 5

e

6

[1] 6

f

For more information about layout, see Custom Layouts.

Warning
  • In narrower displays, such as on smartphones, the layout may not appear to work.
  • The layout argument is intended for very simple use cases, so complex layouts may not work.

heading_levels

Use the heading_levels argument if you want the heading to be displayed as normal headings instead of tabsets. heading_levels and tabset_vars correspond in order. Each tabset_vars is expressed as the heading of specified in heading_levels. If the element of heading_levels is NA, then the element of its tabset_vars is represented as tabset.

Example 1

For example, group1 should be tabset and group2 should be h4 heading.

```{r}
#| results: asis

df1 |>
  render_tabset(
    c(group1, group2),
    c(var1, var2, var3),
    heading_levels = c(NA, 4)
  )
```

X

1

[1] 1

a

Y

2

[1] 2

b

Z

3

[1] 3

c

X

4

[1] 4

d

Y

5

[1] 5

e

Z

6

[1] 6

f

Example 2

Conversely, group1 should be heading 4 and group2 should be tabset.

```{r}
#| results: asis

df1 |>
  render_tabset(
    c(group1, group2),
    c(var1, var2, var3),
    heading_levels = c(4, NA)
  )
```

A

1

[1] 1

a

2

[1] 2

b

3

[1] 3

c

B

4

[1] 4

d

5

[1] 5

e

6

[1] 6

f

Example 3

Set group1 to heading 4 and group2 to heading 5 (no tabset).

df1 |>
  render_tabset(
    c(group1, group2),
    c(var1, var2, var3),
    heading_levels = c(4, 5)
  )

A

X

1

[1] 1

a

Y

2

[1] 2

b

Z

3

[1] 3

c

B

X

4

[1] 4

d

Y

5

[1] 5

e

Z

6

[1] 6

f

pills

As of 2025-03-05, the latest version of Quarto is 1.6, but the Bootstrap version used appears to be Bootstrap 5.2.2, which was introduced with Quarto 1.4.

Several tab customisations are available in Bootstrap 5.2. One of these is pills.

```{r}
#| results: asis

df1 |>
  render_tabset(
    c(group1, group2),
    c(var1, var2, var3),
    pills = TRUE
  )
```

tabset_width

Similarly, you can choose from three fill and justify. In the following, long labels are created for the sake of example and displayed at half width.

“default”

```{r}
#| results: asis
#| layout-ncol: 2

df1_long_label <- df1 |>
  mutate(
    group1 = paste("This is a long label for", group1)
  )

df1_long_label |>
  render_tabset(
    c(group1, group2),
    c(var1, var2, var3),
    tabset_width = "default"
  )
```

1

[1] 1

a

2

[1] 2

b

3

[1] 3

c

4

[1] 4

d

5

[1] 5

e

6

[1] 6

f

“fill”

```{r}
#| results: asis
#| layout-ncol: 2

df1_long_label |>
  render_tabset(
    c(group1, group2),
    c(var1, var2, var3),
    tabset_width = "fill"
  )
```

“justified”

```{r}
#| results: asis
#| layout-ncol: 2

df1_long_label |>
  render_tabset(
    c(group1, group2),
    c(var1, var2, var3),
    tabset_width = "justified"
  )
```

Figures and tables

This section shows more practical examples. Use the mtcars dataset, grouped by cyl and am, to create figures and tables showing the relationship between wt and mpg. render_tabset() was originally created to represent figures and tables as tabsets, with nested data frames as input. Nesting approach is useful when the same operation is performed on each group.

nest() + map()

We shows how to use tidyr::nest() and purrr::map() combination.

For more information on the nest, see follows:

Japanese

# new sample data
df2 <- mtcars |>
  # make groups more explicit
  mutate(
    cyl = paste("cyl:", cyl),
    am = paste("am:", am)
  ) |>
  # nest
  nest(.by = c(cyl, am)) |>
  mutate(
    # create titles for figures
    title = paste(cyl, am, sep = ", "),
    # create scatter plots
    fig = map2(
      data,
      title,
      \(data, title) {
        data |>
          ggplot(aes(wt, mpg)) +
          geom_point() +
          labs(title = title)
      }
    ),
    # create tables
    tbl = map(
      data,
      \(data) {
        data |>
          select(wt, mpg) |>
          knitr::kable()
      }
    )
  )

df2
# A tibble: 6 × 6
  cyl    am    data              title         fig    tbl            
  <chr>  <chr> <list>            <chr>         <list> <list>         
1 cyl: 6 am: 1 <tibble [3 × 9]>  cyl: 6, am: 1 <gg>   <kntr_kbl [5]> 
2 cyl: 4 am: 1 <tibble [8 × 9]>  cyl: 4, am: 1 <gg>   <kntr_kbl [10]>
3 cyl: 6 am: 0 <tibble [4 × 9]>  cyl: 6, am: 0 <gg>   <kntr_kbl [6]> 
4 cyl: 8 am: 0 <tibble [12 × 9]> cyl: 8, am: 0 <gg>   <kntr_kbl [14]>
5 cyl: 4 am: 0 <tibble [3 × 9]>  cyl: 4, am: 0 <gg>   <kntr_kbl [5]> 
6 cyl: 8 am: 1 <tibble [2 × 9]>  cyl: 8, am: 1 <gg>   <kntr_kbl [4]> 

Figures and tables have been created for the fig and tbl columns respectively.

nest_by() + list()

Another method is to use dplyr::nest_by() and list(). This approach is simpler and more intuitive to write.

For more information, see follows:

df2_rowwise <- mtcars |>
  # make groups more explicit
  mutate(
    cyl = paste("cyl:", cyl),
    am = paste("am:", am)
  ) |>
  # nest
  nest_by(cyl, am) |>
  mutate(
    # create titles for figures
    title = paste(cyl, am, sep = ", "),
    # create scatter plots
    fig = list(
      data |>
        ggplot(aes(wt, mpg)) +
        geom_point() +
        labs(title = title)
    ),
    # create tables
    tbl = list(
      data |>
        select(wt, mpg) |>
        knitr::kable()
    )
  )

df2_rowwise
# A tibble: 6 × 6
# Rowwise:  cyl, am
  cyl    am                  data title         fig    tbl            
  <chr>  <chr> <list<tibble[,9]>> <chr>         <list> <list>         
1 cyl: 4 am: 0            [3 × 9] cyl: 4, am: 0 <gg>   <kntr_kbl [5]> 
2 cyl: 4 am: 1            [8 × 9] cyl: 4, am: 1 <gg>   <kntr_kbl [10]>
3 cyl: 6 am: 0            [4 × 9] cyl: 6, am: 0 <gg>   <kntr_kbl [6]> 
4 cyl: 6 am: 1            [3 × 9] cyl: 6, am: 1 <gg>   <kntr_kbl [5]> 
5 cyl: 8 am: 0           [12 × 9] cyl: 8, am: 0 <gg>   <kntr_kbl [14]>
6 cyl: 8 am: 1            [2 × 9] cyl: 8, am: 1 <gg>   <kntr_kbl [4]> 

This way, the values of other columns in the list() can be used freely. (In the nest() + map() method, it was necessary to define in advance which columns to use when calling in the map()).

The outputs are grouped row-wise and already sorted by cly and am.

Figures

In the following, df2 is used. (Works in the same way if you use df2_rowwise).

Warning

When specifying a list-type column that includes ggplot objects in output_vars, setting the chunk option echo: fenced may cause the plots to not display correctly.

```{r}
#| results: asis

df2 |>
  render_tabset(c(cyl, am), fig)
```

Tables

```{r}
#| results: asis

df2 |>
  render_tabset(c(cyl, am), tbl)
```
wt mpg
3.190 24.4
3.150 22.8
2.465 21.5
wt mpg
2.320 22.8
2.200 32.4
1.615 30.4
1.835 33.9
1.935 27.3
2.140 26.0
1.513 30.4
2.780 21.4
wt mpg
3.215 21.4
3.460 18.1
3.440 19.2
3.440 17.8
wt mpg
2.620 21.0
2.875 21.0
2.770 19.7
wt mpg
3.440 18.7
3.570 14.3
4.070 16.4
3.730 17.3
3.780 15.2
5.250 10.4
5.424 10.4
5.345 14.7
3.520 15.5
3.435 15.2
3.840 13.3
3.845 19.2
wt mpg
3.17 15.8
3.57 15.0

Figures and tables

```{r}
#| results: asis

df2 |>
  render_tabset(c(cyl, am), c(fig, tbl))
```

wt mpg
3.190 24.4
3.150 22.8
2.465 21.5

wt mpg
2.320 22.8
2.200 32.4
1.615 30.4
1.835 33.9
1.935 27.3
2.140 26.0
1.513 30.4
2.780 21.4

wt mpg
3.215 21.4
3.460 18.1
3.440 19.2
3.440 17.8

wt mpg
2.620 21.0
2.875 21.0
2.770 19.7

wt mpg
3.440 18.7
3.570 14.3
4.070 16.4
3.730 17.3
3.780 15.2
5.250 10.4
5.424 10.4
5.345 14.7
3.520 15.5
3.435 15.2
3.840 13.3
3.845 19.2

wt mpg
3.17 15.8
3.57 15.0

layout

Use the layout argument to display figure and table side by side with a width of 7:3.

```{r}
#| results: asis

df2 |>
  render_tabset(
    c(cyl, am),
    c(fig, tbl),
    layout = '::: {layout="[7, 3]"}'
  )
```

wt mpg
3.190 24.4
3.150 22.8
2.465 21.5

wt mpg
2.320 22.8
2.200 32.4
1.615 30.4
1.835 33.9
1.935 27.3
2.140 26.0
1.513 30.4
2.780 21.4

wt mpg
3.215 21.4
3.460 18.1
3.440 19.2
3.440 17.8

wt mpg
2.620 21.0
2.875 21.0
2.770 19.7

wt mpg
3.440 18.7
3.570 14.3
4.070 16.4
3.730 17.3
3.780 15.2
5.250 10.4
5.424 10.4
5.345 14.7
3.520 15.5
3.435 15.2
3.840 13.3
3.845 19.2

wt mpg
3.17 15.8
3.57 15.0

Advanced examples

Pre-saved figures

Simply format the path to the saved figure like ![<caption>](<path/to/figure.png>) and execute render_tabset() as before.

# directory for saving figures
dir_fig <- "figures"

# create the directory
dir.create(dir_fig)

# new sample data
df3 <- df2 |>
  mutate(
    # Create file names to save
    fig_path = file.path(
      dir_fig,
      paste0(gsub("[[:punct:]]\\s", "_", title), "_map2_chr.png")
    ),
    # To make the return value a character vector, use `map2_chr()`
    fig_path_md = map2_chr(
      fig,
      fig_path,
      \(p, path) {
        # save figure
        ggsave(path, p)
        # format path to markdown style
        sprintf("![This is a caption for %s.](%s)", path, path)
      }
    )
  ) |>
  select(cyl, am, fig_path_md)

df3
# A tibble: 6 × 3
  cyl    am    fig_path_md                                                      
  <chr>  <chr> <chr>                                                            
1 cyl: 6 am: 1 ![This is a caption for figures/cyl_6_am_1_map2_chr.png.](figure…
2 cyl: 4 am: 1 ![This is a caption for figures/cyl_4_am_1_map2_chr.png.](figure…
3 cyl: 6 am: 0 ![This is a caption for figures/cyl_6_am_0_map2_chr.png.](figure…
4 cyl: 8 am: 0 ![This is a caption for figures/cyl_8_am_0_map2_chr.png.](figure…
5 cyl: 4 am: 0 ![This is a caption for figures/cyl_4_am_0_map2_chr.png.](figure…
6 cyl: 8 am: 1 ![This is a caption for figures/cyl_8_am_1_map2_chr.png.](figure…

Then execute render_tabset() as in basic usage.

```{r}
#| results: asis

df3 |>
  render_tabset(c(cyl, am), fig_path_md)
```

This is a caption for figures/cyl_4_am_0_map2_chr.png.

This is a caption for figures/cyl_4_am_1_map2_chr.png.

This is a caption for figures/cyl_6_am_0_map2_chr.png.

This is a caption for figures/cyl_6_am_1_map2_chr.png.

This is a caption for figures/cyl_8_am_0_map2_chr.png.

This is a caption for figures/cyl_8_am_1_map2_chr.png.
nest_by()

Replace the above nest() + map() method with rowwise().

df3_rowwise <- df2_rowwise |>
  mutate(
    # Create file names to save
    fig_path = file.path(
      dir_fig,
      paste0(gsub("[[:punct:]]\\s", "_", title), "_rowwise.png")
    ),
    fig_path_md = {
      # save figure
      ggsave(fig_path, fig)
      # format path to markdown style
      sprintf("![This is a caption for %s.](%s)", fig_path, fig_path)
    }
  ) |>
  select(cyl, am, fig_path_md)

df3_rowwise
# A tibble: 6 × 3
# Rowwise:  cyl, am
  cyl    am    fig_path_md                                                      
  <chr>  <chr> <chr>                                                            
1 cyl: 4 am: 0 ![This is a caption for figures/cyl_4_am_0_rowwise.png.](figures…
2 cyl: 4 am: 1 ![This is a caption for figures/cyl_4_am_1_rowwise.png.](figures…
3 cyl: 6 am: 0 ![This is a caption for figures/cyl_6_am_0_rowwise.png.](figures…
4 cyl: 6 am: 1 ![This is a caption for figures/cyl_6_am_1_rowwise.png.](figures…
5 cyl: 8 am: 0 ![This is a caption for figures/cyl_8_am_0_rowwise.png.](figures…
6 cyl: 8 am: 1 ![This is a caption for figures/cyl_8_am_1_rowwise.png.](figures…

Then execute render_tabset() as in basic usage.

```{r}
#| results: asis

df3_rowwise |>
  render_tabset(c(cyl, am), fig_path_md)
```

This is a caption for figures/cyl_4_am_0_rowwise.png.

This is a caption for figures/cyl_4_am_1_rowwise.png.

This is a caption for figures/cyl_6_am_0_rowwise.png.

This is a caption for figures/cyl_6_am_1_rowwise.png.

This is a caption for figures/cyl_8_am_0_rowwise.png.

This is a caption for figures/cyl_8_am_1_rowwise.png.

Resolve JavaScript dependencies

When outputting tables or figures that use JavaScript (such as {plotly}, {leaflet}, {DT}, {reactable}, etc.), it seems JavaScript dependencies need to be resolved. The easiest way seems to output them once in a separate chunk.

References:

For example, we use {plotly} to create interactive figures. Simply apply plotly::ggplotly() to the already created ggplot object. Then it needs to be passed to htmltools::div().

df4 <- df2 |>
  mutate(
    fig_plotly = map(
      fig,
      \(p) {
        ggplotly(p) |>
          htmltools::div()
      }
    )
  ) |>
  select(cyl, am, fig_plotly)

df4
# A tibble: 6 × 3
  cyl    am    fig_plotly
  <chr>  <chr> <list>    
1 cyl: 6 am: 1 <shiny.tg>
2 cyl: 4 am: 1 <shiny.tg>
3 cyl: 6 am: 0 <shiny.tg>
4 cyl: 8 am: 0 <shiny.tg>
5 cyl: 4 am: 0 <shiny.tg>
6 cyl: 8 am: 1 <shiny.tg>

As mentioned above, we need a chunk that only runs plot_ly(). Set #| include: false so that this chunk and its output will not appear on the report.

```{r}
#| include: false

plot_ly()
```

Then execute render_tabset() as in basic usage.

```{r}
#| results: asis

df4 |>
  render_tabset(c(cyl, am), fig_plotly)
```

Tables

Here we will show you how to use render_tabset() in a popular package for rendering tables. This example uses knitr::kable(), gt::gt(), gt::opt_interactive(), flextable::flextable(), DT::datatable(), reactable::reactable() and tinytable::tt().

tables <-
  df2 |>
  select(cyl, am, data) |>
  mutate(
    kable = map(data, knitr::kable),
    gt = map(data, gt::gt),
    gt_interactive = map(gt, gt::opt_interactive),
    tt = map(data, tinytable::tt),
    flex = map_chr(
      data,
      \(data) {
        flextable::flextable(data) |>
          knitr::knit_print()
      }
    ),
    DT = map(
      data,
      \(data) {
        DT::datatable(data) |>
          htmltools::div()
      }
    ),
    reac = map(
      data,
      \(data) {
        reactable::reactable(data) |>
          htmltools::div()
      }
    ),
    section_kable = "#### knitr::kable()",
    section_gt = "#### gt::gt()",
    section_gt_interactive = paste(
      "#### gt::gt() |> gt::opt_interactive()",
      "(and run in a separate chunk)"
    ),
    section_tt = "#### tinytable::tt()",
    section_flex = paste(
      "#### flextable::flextable() |> knitr::knit_print()",
      "(using map_chr())"
    ),
    section_DT = paste(
      "#### DT::datatable() |> htmltools::div()",
      "(and run in a separate chunk)"
    ),
    section_reac = paste(
      "#### reactable::reactable() |> htmltools::div()",
      "(and run in a separate chunk)"
    )
  )

tables
# A tibble: 6 × 17
  cyl    am    data     kable      gt       gt_interactive tt             flex  
  <chr>  <chr> <list>   <list>     <list>   <list>         <list>         <chr> 
1 cyl: 6 am: 1 <tibble> <kntr_kbl> <gt_tbl> <gt_tbl [17]>  <tinytabl[,9]> "\n``…
2 cyl: 4 am: 1 <tibble> <kntr_kbl> <gt_tbl> <gt_tbl [17]>  <tinytabl[,9]> "\n``…
3 cyl: 6 am: 0 <tibble> <kntr_kbl> <gt_tbl> <gt_tbl [17]>  <tinytabl[,9]> "\n``…
4 cyl: 8 am: 0 <tibble> <kntr_kbl> <gt_tbl> <gt_tbl [17]>  <tinytabl[,9]> "\n``…
5 cyl: 4 am: 0 <tibble> <kntr_kbl> <gt_tbl> <gt_tbl [17]>  <tinytabl[,9]> "\n``…
6 cyl: 8 am: 1 <tibble> <kntr_kbl> <gt_tbl> <gt_tbl [17]>  <tinytabl[,9]> "\n``…
# ℹ 9 more variables: DT <list>, reac <list>, section_kable <chr>,
#   section_gt <chr>, section_gt_interactive <chr>, section_tt <chr>,
#   section_flex <chr>, section_DT <chr>, section_reac <chr>

knitr::kable(), gt::gt(), and tinytable::tt() are the simplest.

The output of flextable::flextable() is managed by the method knitr::knit_print(). After execution, raw HTML is obtained, which is turned into a character type column using map_chr().

gt::opt_interactive(), {DT} and {reactable} use JavaScript. They should be wrapped with htmltools::div(), except for gt::opt_interactive(), and run in a separate chunk to resolve javascript dependencies. Don’t forget #| include: false.

```{r}
#| include: false

# Here mtcars are specified as dummy data, 
# but any data frame should be acceptable
gt::gt(mtcars) |>
  gt::opt_interactive()

DT::datatable(mtcars)

reactable::reactable(mtcars)
```

Then execute render_tabset(). To make the results easier to see, sections are also to be added.

```{r}
#| results: asis

tables |>
  render_tabset(
    c(cyl, am),
    c(
      section_kable,
      kable,
      section_gt,
      gt,
      section_gt_interactive,
      gt_interactive,
      section_tt,
      tt,
      section_flex,
      flex,
      section_DT,
      DT,
      section_reac,
      reac
    )
  )
```

knitr::kable()

mpg disp hp drat wt qsec vs gear carb
24.4 146.7 62 3.69 3.190 20.00 1 4 2
22.8 140.8 95 3.92 3.150 22.90 1 4 2
21.5 120.1 97 3.70 2.465 20.01 1 3 1

gt::gt()

mpg disp hp drat wt qsec vs gear carb
24.4 146.7 62 3.69 3.190 20.00 1 4 2
22.8 140.8 95 3.92 3.150 22.90 1 4 2
21.5 120.1 97 3.70 2.465 20.01 1 3 1

gt::gt() |> gt::opt_interactive() (and run in a separate chunk)

tinytable::tt()

mpg disp hp drat wt qsec vs gear carb
24.4 146.7 62 3.69 3.190 20.00 1 4 2
22.8 140.8 95 3.92 3.150 22.90 1 4 2
21.5 120.1 97 3.70 2.465 20.01 1 3 1

flextable::flextable() |> knitr::knit_print() (using map_chr())

mpg

disp

hp

drat

wt

qsec

vs

gear

carb

24.4

146.7

62

3.69

3.190

20.00

1

4

2

22.8

140.8

95

3.92

3.150

22.90

1

4

2

21.5

120.1

97

3.70

2.465

20.01

1

3

1

DT::datatable() |> htmltools::div() (and run in a separate chunk)

reactable::reactable() |> htmltools::div() (and run in a separate chunk)

knitr::kable()

mpg disp hp drat wt qsec vs gear carb
22.8 108.0 93 3.85 2.320 18.61 1 4 1
32.4 78.7 66 4.08 2.200 19.47 1 4 1
30.4 75.7 52 4.93 1.615 18.52 1 4 2
33.9 71.1 65 4.22 1.835 19.90 1 4 1
27.3 79.0 66 4.08 1.935 18.90 1 4 1
26.0 120.3 91 4.43 2.140 16.70 0 5 2
30.4 95.1 113 3.77 1.513 16.90 1 5 2
21.4 121.0 109 4.11 2.780 18.60 1 4 2

gt::gt()

mpg disp hp drat wt qsec vs gear carb
22.8 108.0 93 3.85 2.320 18.61 1 4 1
32.4 78.7 66 4.08 2.200 19.47 1 4 1
30.4 75.7 52 4.93 1.615 18.52 1 4 2
33.9 71.1 65 4.22 1.835 19.90 1 4 1
27.3 79.0 66 4.08 1.935 18.90 1 4 1
26.0 120.3 91 4.43 2.140 16.70 0 5 2
30.4 95.1 113 3.77 1.513 16.90 1 5 2
21.4 121.0 109 4.11 2.780 18.60 1 4 2

gt::gt() |> gt::opt_interactive() (and run in a separate chunk)

tinytable::tt()

mpg disp hp drat wt qsec vs gear carb
22.8 108.0 93 3.85 2.320 18.61 1 4 1
32.4 78.7 66 4.08 2.200 19.47 1 4 1
30.4 75.7 52 4.93 1.615 18.52 1 4 2
33.9 71.1 65 4.22 1.835 19.90 1 4 1
27.3 79.0 66 4.08 1.935 18.90 1 4 1
26.0 120.3 91 4.43 2.140 16.70 0 5 2
30.4 95.1 113 3.77 1.513 16.90 1 5 2
21.4 121.0 109 4.11 2.780 18.60 1 4 2

flextable::flextable() |> knitr::knit_print() (using map_chr())

mpg

disp

hp

drat

wt

qsec

vs

gear

carb

22.8

108.0

93

3.85

2.320

18.61

1

4

1

32.4

78.7

66

4.08

2.200

19.47

1

4

1

30.4

75.7

52

4.93

1.615

18.52

1

4

2

33.9

71.1

65

4.22

1.835

19.90

1

4

1

27.3

79.0

66

4.08

1.935

18.90

1

4

1

26.0

120.3

91

4.43

2.140

16.70

0

5

2

30.4

95.1

113

3.77

1.513

16.90

1

5

2

21.4

121.0

109

4.11

2.780

18.60

1

4

2

DT::datatable() |> htmltools::div() (and run in a separate chunk)

reactable::reactable() |> htmltools::div() (and run in a separate chunk)

knitr::kable()

mpg disp hp drat wt qsec vs gear carb
21.4 258.0 110 3.08 3.215 19.44 1 3 1
18.1 225.0 105 2.76 3.460 20.22 1 3 1
19.2 167.6 123 3.92 3.440 18.30 1 4 4
17.8 167.6 123 3.92 3.440 18.90 1 4 4

gt::gt()

mpg disp hp drat wt qsec vs gear carb
21.4 258.0 110 3.08 3.215 19.44 1 3 1
18.1 225.0 105 2.76 3.460 20.22 1 3 1
19.2 167.6 123 3.92 3.440 18.30 1 4 4
17.8 167.6 123 3.92 3.440 18.90 1 4 4

gt::gt() |> gt::opt_interactive() (and run in a separate chunk)

tinytable::tt()

mpg disp hp drat wt qsec vs gear carb
21.4 258.0 110 3.08 3.215 19.44 1 3 1
18.1 225.0 105 2.76 3.460 20.22 1 3 1
19.2 167.6 123 3.92 3.440 18.30 1 4 4
17.8 167.6 123 3.92 3.440 18.90 1 4 4

flextable::flextable() |> knitr::knit_print() (using map_chr())

mpg

disp

hp

drat

wt

qsec

vs

gear

carb

21.4

258.0

110

3.08

3.215

19.44

1

3

1

18.1

225.0

105

2.76

3.460

20.22

1

3

1

19.2

167.6

123

3.92

3.440

18.30

1

4

4

17.8

167.6

123

3.92

3.440

18.90

1

4

4

DT::datatable() |> htmltools::div() (and run in a separate chunk)

reactable::reactable() |> htmltools::div() (and run in a separate chunk)

knitr::kable()

mpg disp hp drat wt qsec vs gear carb
21.0 160 110 3.90 2.620 16.46 0 4 4
21.0 160 110 3.90 2.875 17.02 0 4 4
19.7 145 175 3.62 2.770 15.50 0 5 6

gt::gt()

mpg disp hp drat wt qsec vs gear carb
21.0 160 110 3.90 2.620 16.46 0 4 4
21.0 160 110 3.90 2.875 17.02 0 4 4
19.7 145 175 3.62 2.770 15.50 0 5 6

gt::gt() |> gt::opt_interactive() (and run in a separate chunk)

tinytable::tt()

mpg disp hp drat wt qsec vs gear carb
21.0 160 110 3.90 2.620 16.46 0 4 4
21.0 160 110 3.90 2.875 17.02 0 4 4
19.7 145 175 3.62 2.770 15.50 0 5 6

flextable::flextable() |> knitr::knit_print() (using map_chr())

mpg

disp

hp

drat

wt

qsec

vs

gear

carb

21.0

160

110

3.90

2.620

16.46

0

4

4

21.0

160

110

3.90

2.875

17.02

0

4

4

19.7

145

175

3.62

2.770

15.50

0

5

6

DT::datatable() |> htmltools::div() (and run in a separate chunk)

reactable::reactable() |> htmltools::div() (and run in a separate chunk)

knitr::kable()

mpg disp hp drat wt qsec vs gear carb
18.7 360.0 175 3.15 3.440 17.02 0 3 2
14.3 360.0 245 3.21 3.570 15.84 0 3 4
16.4 275.8 180 3.07 4.070 17.40 0 3 3
17.3 275.8 180 3.07 3.730 17.60 0 3 3
15.2 275.8 180 3.07 3.780 18.00 0 3 3
10.4 472.0 205 2.93 5.250 17.98 0 3 4
10.4 460.0 215 3.00 5.424 17.82 0 3 4
14.7 440.0 230 3.23 5.345 17.42 0 3 4
15.5 318.0 150 2.76 3.520 16.87 0 3 2
15.2 304.0 150 3.15 3.435 17.30 0 3 2
13.3 350.0 245 3.73 3.840 15.41 0 3 4
19.2 400.0 175 3.08 3.845 17.05 0 3 2

gt::gt()

mpg disp hp drat wt qsec vs gear carb
18.7 360.0 175 3.15 3.440 17.02 0 3 2
14.3 360.0 245 3.21 3.570 15.84 0 3 4
16.4 275.8 180 3.07 4.070 17.40 0 3 3
17.3 275.8 180 3.07 3.730 17.60 0 3 3
15.2 275.8 180 3.07 3.780 18.00 0 3 3
10.4 472.0 205 2.93 5.250 17.98 0 3 4
10.4 460.0 215 3.00 5.424 17.82 0 3 4
14.7 440.0 230 3.23 5.345 17.42 0 3 4
15.5 318.0 150 2.76 3.520 16.87 0 3 2
15.2 304.0 150 3.15 3.435 17.30 0 3 2
13.3 350.0 245 3.73 3.840 15.41 0 3 4
19.2 400.0 175 3.08 3.845 17.05 0 3 2

gt::gt() |> gt::opt_interactive() (and run in a separate chunk)

tinytable::tt()

mpg disp hp drat wt qsec vs gear carb
18.7 360.0 175 3.15 3.440 17.02 0 3 2
14.3 360.0 245 3.21 3.570 15.84 0 3 4
16.4 275.8 180 3.07 4.070 17.40 0 3 3
17.3 275.8 180 3.07 3.730 17.60 0 3 3
15.2 275.8 180 3.07 3.780 18.00 0 3 3
10.4 472.0 205 2.93 5.250 17.98 0 3 4
10.4 460.0 215 3.00 5.424 17.82 0 3 4
14.7 440.0 230 3.23 5.345 17.42 0 3 4
15.5 318.0 150 2.76 3.520 16.87 0 3 2
15.2 304.0 150 3.15 3.435 17.30 0 3 2
13.3 350.0 245 3.73 3.840 15.41 0 3 4
19.2 400.0 175 3.08 3.845 17.05 0 3 2

flextable::flextable() |> knitr::knit_print() (using map_chr())

mpg

disp

hp

drat

wt

qsec

vs

gear

carb

18.7

360.0

175

3.15

3.440

17.02

0

3

2

14.3

360.0

245

3.21

3.570

15.84

0

3

4

16.4

275.8

180

3.07

4.070

17.40

0

3

3

17.3

275.8

180

3.07

3.730

17.60

0

3

3

15.2

275.8

180

3.07

3.780

18.00

0

3

3

10.4

472.0

205

2.93

5.250

17.98

0

3

4

10.4

460.0

215

3.00

5.424

17.82

0

3

4

14.7

440.0

230

3.23

5.345

17.42

0

3

4

15.5

318.0

150

2.76

3.520

16.87

0

3

2

15.2

304.0

150

3.15

3.435

17.30

0

3

2

13.3

350.0

245

3.73

3.840

15.41

0

3

4

19.2

400.0

175

3.08

3.845

17.05

0

3

2

DT::datatable() |> htmltools::div() (and run in a separate chunk)

reactable::reactable() |> htmltools::div() (and run in a separate chunk)

knitr::kable()

mpg disp hp drat wt qsec vs gear carb
15.8 351 264 4.22 3.17 14.5 0 5 4
15.0 301 335 3.54 3.57 14.6 0 5 8

gt::gt()

mpg disp hp drat wt qsec vs gear carb
15.8 351 264 4.22 3.17 14.5 0 5 4
15.0 301 335 3.54 3.57 14.6 0 5 8

gt::gt() |> gt::opt_interactive() (and run in a separate chunk)

tinytable::tt()

mpg disp hp drat wt qsec vs gear carb
15.8 351 264 4.22 3.17 14.5 0 5 4
15.0 301 335 3.54 3.57 14.6 0 5 8

flextable::flextable() |> knitr::knit_print() (using map_chr())

mpg

disp

hp

drat

wt

qsec

vs

gear

carb

15.8

351

264

4.22

3.17

14.5

0

5

4

15.0

301

335

3.54

3.57

14.6

0

5

8

DT::datatable() |> htmltools::div() (and run in a separate chunk)

reactable::reactable() |> htmltools::div() (and run in a separate chunk)

References

As this function is focused on quickly and dynamically generating tabsets and chunks, it is difficult to customize it on a chunk-by-chunk basis. The regular way to dynamically create chunks is to use functions such as knitr::knit(), knitr::knit_child(), knitr::knit_expand(), etc. For more information on these, see the following links.

Session Info

# save the session info as an object
sess <- sessioninfo::session_info(pkgs = "attached")

# inject the Quarto info
sess$platform$quarto <- paste(
  quarto::quarto_version(),
  "@",
  normalizePath(quarto::quarto_path())
)

# print it out
sess
─ Session info ───────────────────────────────────────────────────────────────
 setting  value
 version  R version 4.4.3 (2025-02-28)
 os       Ubuntu 24.04.2 LTS
 system   x86_64, linux-gnu
 ui       X11
 language (EN)
 collate  C.UTF-8
 ctype    C.UTF-8
 tz       Etc/UTC
 date     2025-03-13
 pandoc   3.4 @ /opt/quarto/bin/tools/ (via rmarkdown)
 quarto   1.6.42 @ /opt/quarto/bin/quarto

─ Packages ───────────────────────────────────────────────────────────────────
 package   * version date (UTC) lib source
 dplyr     * 1.1.4   2023-11-17 [2] RSPM (R 4.4.0)
 DT        * 0.33    2024-04-04 [2] RSPM (R 4.4.0)
 flextable * 0.9.7   2024-10-27 [2] RSPM (R 4.4.0)
 ggplot2   * 3.5.1   2024-04-23 [2] RSPM (R 4.4.0)
 gt        * 0.11.1  2024-10-04 [2] RSPM (R 4.4.0)
 htmltools * 0.5.8.1 2024-04-04 [2] RSPM (R 4.4.0)
 knitr     * 1.49    2024-11-08 [2] RSPM (R 4.4.0)
 plotly    * 4.10.4  2024-01-13 [2] RSPM (R 4.4.0)
 purrr     * 1.0.4   2025-02-05 [2] RSPM (R 4.4.0)
 quartabs  * 0.1.0   2025-03-13 [1] local
 reactable * 0.4.4   2023-03-12 [2] RSPM (R 4.4.0)
 tibble    * 3.2.1   2023-03-20 [2] RSPM (R 4.4.2)
 tidyr     * 1.3.1   2024-01-24 [2] RSPM (R 4.4.0)
 tinytable * 0.7.0   2025-01-24 [2] RSPM (R 4.4.0)

 [1] /usr/local/lib/R/site-library
 [2] /usr/lib/R/site-library
 [3] /usr/lib/R/library
 * ── Packages attached to the search path.

──────────────────────────────────────────────────────────────────────────────