10.2 The kableExtra package

The kableExtra package (Zhu 2024) is designed to extend the basic functionality of tables produced using knitr::kable() (see Section 10.1). Since knitr::kable() is simple by design (please feel free to read this as “Yihui is lazy”), it definitely has a lot of missing features that are commonly seen in other packages, and kableExtra has filled the gap perfectly. The most amazing thing about kableExtra is that most of its table features work for both HTML and PDF formats (e.g., making striped tables like the one in Figure 10.1).

This package can be installed from CRAN as usual, or you may try the development version on GitHub (https://github.com/haozhu233/kableExtra):

# install from CRAN
install.packages("kableExtra")

# install the development version
remotes::install_github("haozhu233/kableExtra")

It has extensive documentation at https://haozhu233.github.io/kableExtra/, which provides a lot of examples on how the kable() output can be customized for either HTML or LaTeX output. We recommend that you read its documentation by yourself, and will only present a handful of examples in this section.

The kableExtra package features the pipe operator, %>%. You can pipe the kable() output to the styling functions of kableExtra, e.g.,

library(knitr)
library(kableExtra)
kable(iris) %>%
  kable_styling(latex_options = "striped")

10.2.1 Set the font size

The function kable_styling() in kableExtra allows you to style the whole table. For example, you can specify the alignment of the table on the page, the width, and the font size of the table. Below is an example of using a smaller font size:

kable(head(iris, 5), booktabs = TRUE) %>%
  kable_styling(font_size = 8)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5.0 3.6 1.4 0.2 setosa

10.2.2 Style specific rows/columns

The functions row_spec() and column_spec() can be used to style individual rows and columns, respectively. In the example below, we make the first row bold and italic, add a black background to the second and third rows while changing the font color to white, underline the fourth row and change its typeface, rotate the fifth row, and strike out the fifth column:

kable(head(iris, 5), align = 'c', booktabs = TRUE) %>%
  row_spec(1, bold = TRUE, italic = TRUE) %>% 
  row_spec(2:3, color = 'white', background = 'black') %>%
  row_spec(4, underline = TRUE, monospace = TRUE) %>% 
  row_spec(5, angle = 45) %>% 
  column_spec(5, strikeout = TRUE)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
5.1 3.5 1.4 0.2 setosa
4.9 3.0 1.4 0.2 setosa
4.7 3.2 1.3 0.2 setosa
4.6 3.1 1.5 0.2 setosa
5.0 3.6 1.4 0.2 setosa

Similarly, you can style individual cells with the cell_spec() function.

10.2.3 Group rows/columns

Rows and columns can be grouped via the functions pack_rows() and add_header_above(), respectively. You can also collapse rows via collapse_rows(), so one cell can span multiple rows. Below is an example that shows a custom table header with grouped columns:

iris2 <- iris[1:5, c(1, 3, 2, 4, 5)]
names(iris2) <- gsub('[.].+', '', names(iris2))
kable(iris2, booktabs = TRUE) %>%
  add_header_above(c("Length" = 2, "Width" = 2, " " = 1)) %>% 
  add_header_above(c("Measurements" = 4, "More attributes" = 1))
Measurements
More attributes
Length
Width
Sepal Petal Sepal Petal Species
5.1 1.4 3.5 0.2 setosa
4.9 1.4 3.0 0.2 setosa
4.7 1.3 3.2 0.2 setosa
4.6 1.5 3.1 0.2 setosa
5.0 1.4 3.6 0.2 setosa

For the named vector in add_header_above(), the names are the text to be shown in the table header, and the integer values of the vector indicate how many columns a name should span, e.g., "Length" = 2 means Length should span two columns.

Below is an example of pack_rows(). The meaning of its index argument is similar to the argument of add_header_above() as we just explained before.

iris3 <- iris[c(1:2, 51:54, 101:103), ]
kable(iris3[, 1:4], booktabs = TRUE) %>% pack_rows(
  index = c("setosa" = 2, "versicolor" = 4, "virginica" = 3)
)
Sepal.Length Sepal.Width Petal.Length Petal.Width
setosa
1 5.1 3.5 1.4 0.2
2 4.9 3.0 1.4 0.2
versicolor
51 7.0 3.2 4.7 1.4
52 6.4 3.2 4.5 1.5
53 6.9 3.1 4.9 1.5
54 5.5 2.3 4.0 1.3
virginica
101 6.3 3.3 6.0 2.5
102 5.8 2.7 5.1 1.9
103 7.1 3.0 5.9 2.1

10.2.4 Scaling down wide tables in LaTeX

There are a few features that are specific to the HTML or LaTeX output format. For example, landscape pages only make sense in LaTeX, so the landscape() function in kableExtra only works for LaTeX output. Below we show an example to scale down a table to fit the page (otherwise it would be too wide):

tab <- kable(tail(mtcars, 5), booktabs = TRUE)
tab  # original table (too wide)
mpg cyl disp hp drat wt qsec vs am gear carb
Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.5 0 1 5 4
Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.5 0 1 5 6
Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.6 0 1 5 8
Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.6 1 1 4 2
tab %>%
  kable_styling(latex_options = "scale_down")
mpg cyl disp hp drat wt qsec vs am gear carb
Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.9 1 1 5 2
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.5 0 1 5 4
Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.5 0 1 5 6
Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.6 0 1 5 8
Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.6 1 1 4 2

You will not see any differences in the above two tables if you are viewing the HTML version.

References

Zhu, Hao. 2024. kableExtra: Construct Complex Table with Kable and Pipe Syntax. http://haozhu233.github.io/kableExtra/.