ggplot2 4.0 and Dark Mode

Author

Josef Fruehwald

Published

September 11, 2025

Doi

Back in April, Quarto v1.7 introduced the ability to display multiple outputs from a single code chunk depending on whether or not the side is in dark mode. This was really exciting for me, because even though I prefer to keep sites in dark mode for personal use, I’ve found that in some presentation and teaching settings, the projector and lighting conditions make dark mode illegible.

To make it work, you add renderings: [light, dark] to your code chunk yaml, then plot the same data twice: the first time with light mode color settings, and the second time with dark mode color settings. If you toggle between light & dark mode on this post, the plot should toggle between a light mode and a dark mode version.

```{r}
#| renderings: 
#|   - light
#|   - dark
#| fig-width: 5
#| fig-height: 3
library(withr)

plot(1:10)

with_par(
  list(bg = "#222", 
       col = "white", 
       fg = "white",
       col.axis = "white",
       col.lab = "white"
       
       ),
  plot(1:10)
)
```

With ggplot, I’ve already semi-customized my default theme for when I source my _defaults.R that looks like this:

library(ggplot2)

theme_set(
  theme_minimal(base_size = 16) +
    theme(
      text = element_text(family = "Public Sans"),
      panel.grid = element_blank(),
      legend.key = element_blank(),
      axis.ticks = element_blank(),
      axis.line = element_line(color = "grey60", linewidth = 0.2),
      legend.background = element_blank()
    )
)
penguins |>
  ggplot(
    aes(bill_len, bill_dep)
  )+
    geom_point(
      aes(color = species)
    ) ->
  plot1

plot1

Then, I had an additional theme_darkmode() I’d add:

theme_darkmode <- function(){
  theme(
    text = element_text(family = "Public Sans", colour = "white"),
    axis.text = element_text(colour = "white"),
    rect = element_rect(colour = "#222", fill = "#222"),
    plot.background = element_rect(fill = "#222", colour = NA),
    panel.background = element_rect(fill = "#424952"),
    strip.background = element_rect(fill="#3d3d3d"),
    strip.text = element_text(color = "white")
  )
}
plot1 + theme_darkmode()

The issue arose in darkmode when I hadn’t mapped the color aesthetic to any data.

penguins |>
  ggplot(
    aes(bill_len, bill_dep)
  )+
    geom_point() ->
  plot2

plot2 + theme_darkmode()

The default point colors weren’t settable by a theme, and I had to use some unpleasant dark rendering functions to get things working nicely.

Redoing it with ggplot2 v4

So, I’m going to rewrite my theme settings to take account of the fact that ggplot2 themes now have “ink” and “paper” color settings you can define. I’ll re-define my default theme with the new theme_sub_*() layers.

theme_set(
  theme_minimal(base_size = 16) +
    theme(
      text = element_text(family = "Public Sans")
    ) +
    theme_sub_panel(
      grid = element_blank(),
    ) +
    theme_sub_legend(
      key = element_blank(),
      background = element_blank()
    ) +
    theme_sub_axis(
      ticks = element_blank(),
      line = element_line(color = "grey60", linewidth = 0.2)
    )
)
plot2

And now I’ll define my darkmode theme:

theme_darkmode <- function(){
  theme_minimal(
    base_size = 16,
    paper = "#222",
    ink = "white"
  ) +
    theme(
      text = element_text(family = "Public Sans")
    ) +
    theme_sub_panel(
      background = element_rect(
        fill = "#424952", color = NA
      ),
      grid = element_blank()
    ) +
    theme_sub_legend(
      key = element_blank(),
      background = element_blank()
    ) +
    theme_sub_axis(
      line = element_line(
        color = "grey60", linewidth = 0.2
      )
    )
}
plot2 +
  theme_darkmode()

So now to have one code chunk with different outputs in light vs dark mode, it’s just

```{r}
#| renderings: 
#|   - light
#|   - dark
plot2
plot2 + theme_darkmode()
```

Reuse

CC-BY 4.0

Citation

BibTeX citation:
@online{fruehwald2025,
  author = {Fruehwald, Josef},
  title = {Ggplot2 4.0 and {Dark} {Mode}},
  series = {Væl Space},
  date = {2025-09-11},
  url = {https://jofrhwld.github.io/blog/posts/2025/09/2025-09-11_ggplot-4-0-and-dark-mode/},
  doi = {10.59350/9vxye-n5q78},
  langid = {en}
}
For attribution, please cite this work as:
Fruehwald, Josef. 2025. “Ggplot2 4.0 and Dark Mode.” Væl Space. September 11, 2025. https://doi.org/10.59350/9vxye-n5q78.