kableExtra: styling knitr tables for HTML and LaTeX with pipes
Construct Complex Table with knitr::kable() + pipe.
At a glance
- What is it?
- kableExtra is an R package that adds features to the output of knitr's kable() through pipe syntax, so a plain data frame becomes a striped, captioned, grouped and footnoted table in either HTML or LaTeX from the same call. It suits R Markdown authors who want more than a bare table without hand-writing HTML or LaTeX, and the package is explicit that it is not a table generator and that the last ten percent of cases still need raw markup.
- Who is it for?
- Adopt kableExtra if you write R Markdown and want the same styled table in both HTML and LaTeX output, because the functions detect the format and pick the right mechanism for you.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 111 days ago.
- What is it written in?
- Mainly R, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Why a package exists to add styling to a table
The README opens with the design of the function this package wraps. knitr's `kable()` is usually a popular choice when talking about table generators in R, because of its ultimate simplicity, and unlike powerful table rendering engines such as xtable, the philosophy behind it is to make it easy for programmers to use. The description quoted from Yihui makes the position explicit: this is a very simple table generator, simple by design, not intended to replace any other R packages for making tables.
The package then explains what that simplicity cost. The ultimate simplicity of `kable()` also brought troubles to some, especially new R users who may not have much experience generating tables. It is not rare to see people, including experienced users, asking how to centre or left-align a table on Stack Overflow. And for the author, the frustration was repeatedly parsing CSS into `kable()` for very simple features like striped lines, and for LaTeX it was worse, being almost Stack Overflow dependent.
That is the origin of the package, and it is a good one. The problem is not that `kable()` is bad, it is that `kable()` deliberately stops at a simple table and there is a long tail of formatting that every R Markdown author needs and nobody wants to write by hand in two output formats.
The stated goal is a division of labour. Use the default base `kable()`, or `pander::pander()` as a good alternative for markdown tables, for all simple tables. Use `kable()` with kableExtra to generate ninety percent of complex, advanced, self-customised and beautiful tables in either HTML or LaTeX. Only have to mess with raw HTML or LaTeX in the last ten percent of cases where kableExtra cannot solve the problem.
The package is on CRAN with a DOI, the last push was on 2026-07-04, and the most recent listed release is v1.4.0 from 2024-01-23.
Pipes, and the explicit refusal to be a table generator
The first feature is pipable syntax, and the README states the design position rather than the feature list: kableExtra is NOT a table generating package. It is a package that can add features to a `kable()` output using a syntax that every useR loves, the pipes `%>%`.
The analogy given is to plots. Similar approaches to deal with plots exist in packages like ggvis and plotly, and the argument is that there is no reason why the same cannot be done with tables. A pipe chain reads as a sequence of transformations, which is the right shape for a table that gains a header, a caption, a footnote and a styling rule in sequence, and it is the shape an R programmer already has in their hands.
The second feature is unified functions for both HTML and PDF. Most functionalities in kableExtra can work in both HTML and PDF, and the mechanism is that as long as you specify the format in `kable()`, which can be set globally through the option `knitr.table.format`, the functions in this package pick the right way to manipulate the table themselves. The example given is that if users want to left align the table, `kable(...) %>% kable_styling(position = "left")` works in both HTML and PDF.
That format detection is the piece that makes the unification work, and it is also the piece to understand before you use the package. A styling function does not have a separate HTML and LaTeX variant because it branches on the format you set. If you set the global option to something other than what your document actually renders, the functions will pick the wrong branch and produce output for the other format.
There is also `kbl()`, introduced more recently, acting as an alternative to `kable()` but providing better documentation and format detection. So there are two entry points: the familiar `kable()` that adds to, and `kbl()` which is the package's own version with its own format detection.
The same call produces an HTML table and a LaTeX table
The basic usage section is the clearest possible demonstration of the unification idea, because it shows the HTML and LaTeX versions of the same table side by side.
library(kableExtra)
dt <- mtcars[1:5, 1:4]
# HTML table
kbl(dt, caption = "Demo Table") %>%
kable_styling(bootstrap_options = "striped",
full_width = F) %>%
add_header_above(c(" ", "Group 1" = 2, "Group 2[note]" = 2)) %>%
footnote(c("table footnote"))
# LaTeX Table
kbl(dt, booktabs = T, caption = "Demo Table") %>%
kable_styling(latex_options = c("striped", "hold_position"),
full_width = F) %>%
add_header_above(c(" ", "Group 1" = 2, "Group 2[note]" = 2)) %>%
footnote(c("table footnote"))Read the two chains and notice what is identical and what differs. The data, the caption, the header grouping, the footnote and the general shape of the chain are the same. What differs is that the HTML version passes `bootstrap_options = "striped"` to `kable_styling`, because that is the Bootstrap CSS table styling, while the LaTeX version passes `booktabs = T` to `kbl()` and `latex_options = c("striped", "hold_position")` to `kable_styling`, because in LaTeX the styling comes from the booktabs package and the options are different names. `full_width = F` is spelled the same in both because the parameter is the same.
The `add_header_above(c(" ", "Group 1" = 2, "Group 2[note]" = 2))` call is the header grouping, and it shows the package's approach to spans. The named vector gives a label and a count of columns, and the empty string with a count of one occupies the first column so the groups line up under the right headers. The `[note]` in the second label is the marker that the footnote refers to.
The `footnote(c("table footnote"))` call then attaches the note to that marker.
The vignette is where the rest lives, and the README links two of them directly, one for creating an HTML table with `knitr::kable()` and kableExtra, with a Chinese version, and one for the LaTeX equivalent as a PDF.
Automatic LaTeX package loading, and the template caveat
There is one piece of behaviour in the package that is worth knowing about because it is invisible when it works and confusing when it does not.
The package can load the required LaTeX package automatically in a vanilla R Markdown. That is, when you render an R Markdown document to PDF and the table needs booktabs or some other LaTeX package, kableExtra inserts the package requirement for you rather than making you add it to the preamble.
For customised R Markdown templates, the recommendation is to load the related LaTeX packages manually. That caveat is the practical instruction to follow, because a custom template is where the automatic mechanism is most likely to conflict with something the template already does or does not include.
The repository layout backs the rest of the package story. There is a `DESCRIPTION` file, a `NAMESPACE`, an `R/` directory with the code, `man/` for the documentation, `tests/`, `vignettes/` for the long-form guides, `inst/` for installed resources, and `docs/` for the rendered site, which is what serves the haozhu233.github.io/kableExtra homepage and the two vignettes the README links. The `kableExtra.Rproj` file is the RStudio project, and a `.Rprofile` is present, which is often a sign of packages that set up a development environment on load.
The vignettes are the reference a serious user needs, and they are organised by output format, one for HTML and one for LaTeX, with a Chinese translation of the HTML one. The README itself defers to them for more information, which is a sensible division: the README shows the shape of the API and the vignettes show the range.
Against a real table engine and against hand-written markup
The comparison worth making is with the two other routes to a styled table in R Markdown.
The first is a real table engine such as xtable, which the README names as one of the powerful table rendering engines. Those packages take over the whole job: they render the data frame, they own the layout, and they do it well. What they do not do is let you keep the `kable()` output you already have and add three things to it. If your document already uses `kable()` everywhere, or if the table is produced by a package that returns `kable()` output, kableExtra is the path that keeps the rest of the document unchanged. The trade is the one the README states plainly: kableExtra is not a table generator, it decorates one.
The second is writing the HTML or LaTeX yourself. The author's own account of why the package exists is that they were repeatedly parsing CSS into `kable()` for features like striped lines, and were nearly dependent on Stack Overflow for LaTeX. So the alternative is not theoretical, it is what people actually did. kableExtra packages the common cases of that work into named functions that emit the right markup for the format you are in.
The honest limit is the ten percent. The package states that you only have to mess with raw HTML or LaTeX in the last ten percent of cases where kableExtra cannot solve the problem, and that is a useful framing because it tells you when to reach for the escape hatch rather than filing an issue. The escape hatch is that you can still write the markup, and the pipe chain does not prevent you from emitting a chunk of raw HTML in the middle of it.
The maintenance picture is worth noting too, and it is the one place where the picture is mixed. The releases are v1.4.0 from 2024-01-23, then v0.6.0 from 2017-10-24 with the note Rainbow bomb, and v0.5.2 from 2017-09-15 called cookie cutter. The gap between 2017 and 2024 is real, and the version numbering suggests the 1.x line is a different generation of the package from the 0.x line that most people will have encountered first. The repository is not archived and the last push was on 2026-07-04, so work has continued after v1.4.0.
Editorial conclusion
Adopt kableExtra if you write R Markdown and want the same styled table in both HTML and LaTeX output, because the functions detect the format and pick the right mechanism for you. Do not adopt it expecting it to replace a full table engine, since the package states plainly that it is not a table generating package and that the remaining ten percent of cases require raw HTML or LaTeX, and check first which output format you set through knitr.table.format, because that global option changes what the formatting functions do.
Frequently asked questions
What does kableExtra do?
It adds features to the output of knitr's kable() using pipe syntax, so a plain table becomes a striped, captioned, grouped and footnoted one. It is not a table generating package; it decorates the output of a table generator.
How do I install kableExtra?
The stable version is on CRAN, so `install.packages("kableExtra")` works. For the development version the README gives `devtools::install_github("haozhu233/kableExtra")`.
Can the same kableExtra code style both HTML and LaTeX tables?
Yes, for most functionality. As long as you specify the format in kable(), which can be set globally through the option knitr.table.format, the functions pick the right way to manipulate the table themselves, so kable(...) %>% kable_styling(position = "left") works in both HTML and PDF.
What is kbl() and how does it differ from kable()?
kbl() is a newer function introduced as an alternative to kable() that provides better documentation and format detection. The README's basic usage example uses kbl() for both the HTML and the LaTeX table.
Does kableExtra load LaTeX packages automatically?
In a vanilla R Markdown it can load the required LaTeX package automatically. For customised R Markdown templates the recommendation is to load the related LaTeX packages manually instead.
Is kableExtra still being maintained?
The repository is not archived and the last push was on 2026-07-04. The latest listed release is v1.4.0 from 2024-01-23, with earlier ones v0.6.0 from 2017-10-24 and v0.5.2 from 2017-09-15, and the package is on CRAN with a Zenodo DOI.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/haozhu233-kableextra)Was this useful?