|
| 1 | +--- |
| 2 | +title: "Using Markdown in HTML Tables" |
| 3 | +format: |
| 4 | + html: |
| 5 | + toc: true |
| 6 | + toc-depth: 3 |
| 7 | +keep-md: true |
| 8 | +vignette: > |
| 9 | + %\VignetteIndexEntry{Using Markdown in HTML Tables} |
| 10 | + %\VignetteEngine{quarto::html} |
| 11 | + %\VignetteEncoding{UTF-8} |
| 12 | +--- |
| 13 | + |
| 14 | +## Introduction |
| 15 | + |
| 16 | +Quarto allows you to include Markdown syntax inside HTML tables, making it possible to add formatting, links, images, and even more complex elements like videos to your table cells. This vignette demonstrates how to use the table helper functions provided by this package to simplify this process. |
| 17 | + |
| 18 | +The main challenge when working with Markdown in HTML tables is that Quarto won't automatically process Markdown content. Quarto addresses this using special `data-qmd` attributes that tell the Quarto processor to interpret the content as Markdown. This package provides helper functions to create these attributes easily. |
| 19 | + |
| 20 | +See Quarto documentation about HTML tables parsing: <https://quarto.org/docs/authoring/tables.html#html-tables>. |
| 21 | + |
| 22 | +## Basic Usage |
| 23 | + |
| 24 | +The table helper functions create HTML elements (`<span>` or `<div>`) with the appropriate `data-qmd` or `qmd-base64` attributes. There are two main types of functions: |
| 25 | + |
| 26 | +1. Functions for creating `<span>` elements: |
| 27 | + - main function is `tbl_qmd_span()`, defaulting to base64 encoding, |
| 28 | + - Two others are explicit versions: `tbl_qmd_span_base64()` and `tbl_qmd_span_raw()` |
| 29 | +2. Functions for creating `<div>` elements: |
| 30 | + - main function is `tbl_qmd_div()`, defaulting to base64 encoding, |
| 31 | + - Two others are explicit versions: `tbl_qmd_div_base64()` and `tbl_qmd_div_raw()` |
| 32 | + |
| 33 | +Base64 encoding is useful when your Markdown content contains special characters or HTML tags, and this is used by default to avoid any escaping problems using this feature. |
| 34 | + |
| 35 | +### Example with a Basic HTML Table |
| 36 | + |
| 37 | +Here's a simple example of creating an HTML table with Markdown content: |
| 38 | + |
| 39 | +```{r} |
| 40 | +library(quarto) |
| 41 | +
|
| 42 | +# Create a simple data frame |
| 43 | +data <- data.frame( |
| 44 | + Column1 = c("Row 1", "Row 2", "Row 3"), |
| 45 | + Column2 = c("Value 1", "Value 2", "Value 3") |
| 46 | +) |
| 47 | +
|
| 48 | +# Function to add Markdown formatting to table cells |
| 49 | +add_markdown <- function(data) { |
| 50 | + data$Column1 <- sapply(data$Column1, function(x) { |
| 51 | + tbl_qmd_span(paste0("**", x, "**")) |
| 52 | + }) |
| 53 | + data$Column2 <- sapply(data$Column2, function(x) { |
| 54 | + tbl_qmd_span(paste0("*", x, "*")) |
| 55 | + }) |
| 56 | + return(data) |
| 57 | +} |
| 58 | +
|
| 59 | +# Apply Markdown formatting |
| 60 | +data_with_md <- add_markdown(data) |
| 61 | +
|
| 62 | +# Display the data frame as an HTML table |
| 63 | +knitr::kable(data_with_md, format = "html", escape = FALSE) |
| 64 | +``` |
| 65 | + |
| 66 | +### Using with knitr::kable() |
| 67 | + |
| 68 | +The `knitr::kable()` function is a common way to create tables in R Markdown and Quarto. By setting `escape = FALSE`, we can include HTML in the table cells: |
| 69 | + |
| 70 | +```{r} |
| 71 | +#| label: tbl-kable-equation |
| 72 | +#| tbl-cap: A table with a math equation rendered using Quarto's data-qmd attribute |
| 73 | +library(quarto) |
| 74 | +
|
| 75 | +# Create a data frame with math expressions |
| 76 | +tbl <- data.frame( |
| 77 | + var = c("$a$", "$b$", "$c$"), |
| 78 | + val = c(1, 2, 3) |
| 79 | +) |
| 80 | +
|
| 81 | +# Add data-qmd attributes to the math expressions |
| 82 | +tbl$var <- sapply(tbl$var, tbl_qmd_span) |
| 83 | +
|
| 84 | +# Create the table |
| 85 | +knitr::kable(tbl, format = "html", escape = FALSE) |
| 86 | +``` |
| 87 | + |
| 88 | +## Advanced Features |
| 89 | + |
| 90 | +### Display Text |
| 91 | + |
| 92 | +Some feature are Quarto features only. If your table can be used in other context than Quarto, you might want to use the `display` argument to provide a text that will be shown in the table instead of the Markdown content, as it won't be processed outside of Quarto documents. |
| 93 | + |
| 94 | +For example, you might want to show a placeholder when using video shortcodes in a table, as the video player won't be rendered outside of Quarto: |
| 95 | + |
| 96 | +```{r} |
| 97 | +#| label: video-placeholder |
| 98 | +# Create a video embed with a display text |
| 99 | +video_embed <- tbl_qmd_span( |
| 100 | + "{{< video https://www.youtube.com/embed/wo9vZccmqwc >}}", |
| 101 | + display = "[Video Player]" |
| 102 | +) |
| 103 | +
|
| 104 | +# Create a data frame with the video embed |
| 105 | +data <- data.frame( |
| 106 | + Content = c("Regular text", video_embed), |
| 107 | + Description = c("Just some text", "A YouTube video") |
| 108 | +) |
| 109 | +
|
| 110 | +# Create the table |
| 111 | +knitr::kable(data, format = "html", escape = FALSE) |
| 112 | +``` |
| 113 | + |
| 114 | +Behavior when the table is not processed by Quarto is simulated by opting-out html table processing for this specific table. For example, when `html-table-processing: none` cell option is set like in the Quarto computation cell below. |
| 115 | + |
| 116 | +```{r} |
| 117 | +#| label: video-placeholder |
| 118 | +#| echo: fenced |
| 119 | +#| html-table-processing: none |
| 120 | +``` |
| 121 | + |
| 122 | +Output above is a HTML table not processed by Quarto, so the video shortcode is not rendered as a video player, but as a regular text. |
| 123 | + |
| 124 | +See more about disabling HTML table processing in the [Quarto documentation](https://quarto.org/docs/authoring/tables.html#disabling-quarto-table-processing). |
| 125 | + |
| 126 | +::: {.callout-important} |
| 127 | + |
| 128 | +## Limitations |
| 129 | + |
| 130 | +Using `data-qmd` or `data-qmd-base64` attributes is a Quarto-specific feature and it will only be working when Quarto is allowed to process HTML tables. If this is used in an environment or a document that do opt-out Quarto HTML table processing, the content will not be rendered as expected. |
| 131 | + |
| 132 | +::: |
| 133 | + |
| 134 | +## Table package integration |
| 135 | + |
| 136 | +### Using with kableExtra |
| 137 | + |
| 138 | +Here's a more complex example that combines all these features to create a complete HTML table with Markdown content: |
| 139 | + |
| 140 | +```{r} |
| 141 | +library(quarto) |
| 142 | +library(kableExtra) |
| 143 | +
|
| 144 | +# Create a data frame with different types of content |
| 145 | +complex_table <- data.frame( |
| 146 | + Feature = c("Formatting", "Math", "References", "Media"), |
| 147 | + Example = c( |
| 148 | + tbl_qmd_span("**Bold**, *italic*, and `code`"), |
| 149 | + tbl_qmd_span("$\\int_{a}^{b} f(x) \\, dx$"), |
| 150 | + tbl_qmd_span("See @tbl-kable-equation for example of a table"), |
| 151 | + tbl_qmd_div( |
| 152 | + "{{< video https://www.youtube.com/embed/wo9vZccmqwc >}}", |
| 153 | + display = "[Video Player]" |
| 154 | + ) |
| 155 | + ), |
| 156 | + Notes = c( |
| 157 | + "Basic markdown formatting", |
| 158 | + "LaTeX math expressions", |
| 159 | + "Cross-references to other document elements", |
| 160 | + "Embedded media using shortcodes" |
| 161 | + ) |
| 162 | +) |
| 163 | +
|
| 164 | +# Create and style the table |
| 165 | +kbl(complex_table, format = "html", escape = FALSE) %>% |
| 166 | + kable_classic() %>% |
| 167 | + column_spec(2, width = "40%") %>% |
| 168 | + row_spec(0, bold = TRUE, background = "#f8f8f8") |
| 169 | +``` |
| 170 | + |
| 171 | + |
| 172 | +### Using with flextable |
| 173 | + |
| 174 | +By design, flextable does not support inserting raw HTML content into its cells. Using the `tbl_qmd_span()` or `tbl_qmd_div()` functions directly in a flextable will not work as expected. |
| 175 | + |
| 176 | +Quarto team will be working with flextable developers to find a way to support this in the future. |
| 177 | + |
| 178 | +### Using with **gt** |
| 179 | + |
| 180 | +The **gt** package provides a way to create tables with rich formatting. **gt** already has built-in support for rendering Markdown content, so you can use it directly without needing the `tbl_qmd_span()` or `tbl_qmd_div()` functions. |
| 181 | + |
| 182 | +Here is the same example as above, but using **gt** with **quarto** R package functions |
| 183 | + |
| 184 | +```{r} |
| 185 | +library(gt) |
| 186 | +gt(complex_table) |> |
| 187 | + fmt_passthrough(columns = "Example", escape = FALSE) |
| 188 | +``` |
| 189 | + |
| 190 | +Here is the example with built-in support for Markdown content in **gt**: |
| 191 | + |
| 192 | +```{r} |
| 193 | +data.frame( |
| 194 | + Feature = c("Formatting", "Math", "References", "Media"), |
| 195 | + Example = c( |
| 196 | + c("**Bold**, *italic*, and `code`"), |
| 197 | + "$\\int_{a}^{b} f(x) \\, dx$", |
| 198 | + "See @tbl-kable-equation for example of a table", |
| 199 | + "{{< video https://www.youtube.com/embed/wo9vZccmqwc >}}" |
| 200 | + ), |
| 201 | + Notes = c( |
| 202 | + "Basic markdown formatting", |
| 203 | + "LaTeX math expressions", |
| 204 | + "Cross-references to other document elements", |
| 205 | + "Embedded media using shortcodes" |
| 206 | + ) |
| 207 | +) |> |
| 208 | + gt() |> |
| 209 | + fmt_markdown(columns = "Example") |
| 210 | +``` |
| 211 | + |
| 212 | +`gt::fmt_markdown()` is aware of Quarto context and it will internally use the `data-qmd` attribute to render Markdown content correctly when Quarto processes the document. |
| 213 | + |
| 214 | +## Conclusion |
| 215 | + |
| 216 | +The table helper functions in this package make it easy to include Markdown content in HTML tables when working with Quarto documents. They will be useful to users to get unblocked when using package that provide HTML tables. Hopefully, developers will also find them useful to simplify the process for users of creating tables with rich content. |
| 217 | + |
| 218 | +For more information about tables in Quarto, see the [Quarto documentation on tables](https://quarto.org/docs/authoring/tables.html#html-tables). |
0 commit comments