diff --git a/NAMESPACE b/NAMESPACE
index eea1693d..f0b94d09 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -43,6 +43,7 @@ export(type_vline)
 importFrom(grDevices,adjustcolor)
 importFrom(grDevices,as.raster)
 importFrom(grDevices,axisTicks)
+importFrom(grDevices,cairo_pdf)
 importFrom(grDevices,col2rgb)
 importFrom(grDevices,colorRampPalette)
 importFrom(grDevices,convertColor)
diff --git a/NEWS.md b/NEWS.md
index 810d1be8..b32e27b9 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -4,11 +4,18 @@ _If you are viewing this file on CRAN, please check the
 [latest NEWS](https://grantmcdermott.com/tinyplot/NEWS.html) on our website
 where the formatting is also better._
 
-## Development
+## 0.3.0.99 (dev version)
 
-Bugs:
+New features:
+
+- `tinyplot(..., file = "*.pdf")` will now default to using `cairo_pdf()` if
+  cairo graphics are supported on the user's machine. This should help to ensure
+  better fidelity of (non-standard) fonts in PDFs. (#311 @grantcdermott)
+
+Bugs fixes:
 
-* The `cex` argument should be respected when using `type="bg"`. Thanks to @rjknell for report #307.
+- The `cex` argument should be respected when using `type="bg"`. Thanks to
+  @rjknell for report #307 and @vincentarelbundock for the fix.
 
 ## 0.3.0
 
diff --git a/R/setup_device.R b/R/setup_device.R
index f93ee78e..e3837748 100644
--- a/R/setup_device.R
+++ b/R/setup_device.R
@@ -14,11 +14,16 @@ setup_device = function(file, width, height) {
     # close interactive device if not already open
     if (isTRUE(fkdev)) dev.off()
     exttype = file_ext(filepath)
-    if (exttype == "jpg") exttype = "jpeg"
+    if (exttype == "pdf" && .tpar[["cairo"]]) {
+      exttype = "cairo"
+    } else if (exttype == "jpg") {
+      exttype = "jpeg"
+    }
     switch(exttype,
       png = png(filepath, width = filewidth, height = fileheight, units = "in", res = fileres),
       jpeg = jpeg(filepath, width = filewidth, height = fileheight, units = "in", res = fileres),
       pdf = pdf(filepath, width = filewidth, height = fileheight),
+      cairo = cairo_pdf(filepath, width = filewidth, height = fileheight),
       svg = svg(filepath, width = filewidth, height = fileheight),
       stop("\nUnsupported file extension. Only '.png', '.jpg', '.pdf', or '.svg' are allowed.\n")
     )
diff --git a/R/tinyplot.R b/R/tinyplot.R
index bc8ea94b..ece4eeab 100644
--- a/R/tinyplot.R
+++ b/R/tinyplot.R
@@ -330,7 +330,7 @@
 #' out existing `plot` calls for `tinyplot` (or its shorthand alias `plt`),
 #' without causing unexpected changes to the output.
 #'
-#' @importFrom grDevices axisTicks adjustcolor colorRampPalette extendrange palette palette.colors palette.pals hcl.colors hcl.pals xy.coords png jpeg pdf svg dev.off dev.new dev.list
+#' @importFrom grDevices axisTicks adjustcolor cairo_pdf colorRampPalette extendrange palette palette.colors palette.pals hcl.colors hcl.pals xy.coords png jpeg pdf svg dev.off dev.new dev.list
 #' @importFrom graphics abline arrows axis Axis box boxplot grconvertX grconvertY hist lines mtext par plot.default plot.new plot.window points polygon polypath segments rect text title
 #' @importFrom utils modifyList head tail
 #' @importFrom stats na.omit
diff --git a/R/tpar.R b/R/tpar.R
index 59a42c8c..d1e662df 100644
--- a/R/tpar.R
+++ b/R/tpar.R
@@ -51,6 +51,7 @@
 #'
 #' * `adj.xlab`: Numeric value between 0 and 1 controlling the alignment of the x-axis label.
 #' * `adj.ylab`: Numeric value between 0 and 1 controlling the alignment of the y-axis label.
+#' * `cairo`: Logical indicating whether \code{\link[grDevices]{cairo_pdf}} should be used when writing plots to PDF. If `FALSE`, then \code{\link[grDevices]{pdf}} will be used instead, with implications for embedding (non-standard) fonts. Only used if `tinyplot(..., file = "<filename>.pdf")` is called. Defaults to the value of `capabilities("cairo")`.
 #' * `dynmar`: Logical indicating whether `tinyplot` should attempt dynamic adjustment of margins to reduce whitespace and/or account for spacing of text elements (e.g., long horizontal y-axis labels). Note that this parameter is tightly coupled to internal `tinythemes()` logic and should _not_ be adjusted manually unless you really know what you are doing or don't mind risking unintended consequences to your plot.
 #' * `facet.bg`: Character or integer specifying the facet background colour. If an integer, will correspond to the user's default colour palette (see `palette`). Passed to `rect`. Defaults to `NULL` (none).
 #' * `facet.border`: Character or integer specifying the facet border colour. If an integer, will correspond to the user's default colour palette (see `palette`). Passed to `rect`. Defaults to `NA` (none).
@@ -66,8 +67,8 @@
 #' * `grid.lwd`: Non-negative numeric giving the line width of the panel grid lines. Defaults to `1`.
 #' * `grid`: Logical indicating whether a background panel grid should be added to plots automatically. Defaults to `NULL`, which is equivalent to `FALSE`.
 #' * `lmar`: A numeric vector of form `c(inner, outer)` that gives the margin padding, in terms of lines, around the automatic `tinyplot` legend. Defaults to `c(1.0, 0.1)`. The inner margin is the gap between the legend and the plot region, and the outer margin is the gap between the legend and the edge of the graphics device.
-#' * `palette.qualitative`: Palette for qualitative colors. See the `palette` argumetn in `?tinyplot`.
-#' * `palette.sequential`: Palette for sequential colors. See the `palette` argumetn in `?tinyplot`.
+#' * `palette.qualitative`: Palette for qualitative colors. See the `palette` argument in `?tinyplot`.
+#' * `palette.sequential`: Palette for sequential colors. See the `palette` argument in `?tinyplot`.
 #' * `ribbon.alpha`: Numeric factor in the range `[0,1]` for modifying the opacity alpha of "ribbon" and "area" type plots. Default value is `0.2`.
 #'
 #' @importFrom graphics par
@@ -219,6 +220,7 @@ known_tpar = c(
     "cex.ylab",
     "col.xaxs",
     "col.yaxs",
+    "cairo",
     "dynmar",
     "facet.bg",
     "facet.border",
@@ -263,6 +265,7 @@ assert_tpar = function(.tpar) {
   assert_numeric(.tpar[["adj.sub"]], len = 1, lower = 0, upper = 1, null.ok = TRUE, name = "adj.sub")
   assert_numeric(.tpar[["adj.xlab"]], len = 1, lower = 0, upper = 1, null.ok = TRUE, name = "adj.xlab")
   assert_numeric(.tpar[["adj.ylab"]], len = 1, lower = 0, upper = 1, null.ok = TRUE, name = "adj.ylab")
+  assert_flag(.tpar[["cairo"]], name = "cairo")
   assert_flag(.tpar[["dynmar"]], null.ok = FALSE, name = "dynmar")
   assert_numeric(.tpar[["lmar"]], len = 2, null.ok = TRUE, name = "lmar")
   assert_numeric(.tpar[["ribbon.alpha"]], len = 1, lower = 0, upper = 1, null.ok = TRUE, name = "ribbon.alpha")
@@ -315,6 +318,9 @@ init_tpar = function(rm_hook = FALSE) {
     }
   }
 
+  .tpar$cairo = if (is.null(getOption("tinyplot_cairo"))) capabilities("cairo") else as.logical(getOption("tinyplot_cairo"))
+  
+  
   .tpar$dynmar = if (is.null(getOption("tinyplot_dynmar"))) FALSE else as.logical(getOption("tinyplot_dynmar"))
   
   # Figure output options if written to file
diff --git a/man/tpar.Rd b/man/tpar.Rd
index 2a937275..c1fc5914 100644
--- a/man/tpar.Rd
+++ b/man/tpar.Rd
@@ -62,6 +62,7 @@ you should rather use \code{par()} instead.
 \itemize{
 \item \code{adj.xlab}: Numeric value between 0 and 1 controlling the alignment of the x-axis label.
 \item \code{adj.ylab}: Numeric value between 0 and 1 controlling the alignment of the y-axis label.
+\item \code{cairo}: Logical indicating whether \code{\link[grDevices]{cairo_pdf}} should be used when writing plots to PDF. If \code{FALSE}, then \code{\link[grDevices]{pdf}} will be used instead, with implications for embedding (non-standard) fonts. Only used if \code{tinyplot(..., file = "<filename>.pdf")} is called. Defaults to the value of \code{capabilities("cairo")}.
 \item \code{dynmar}: Logical indicating whether \code{tinyplot} should attempt dynamic adjustment of margins to reduce whitespace and/or account for spacing of text elements (e.g., long horizontal y-axis labels). Note that this parameter is tightly coupled to internal \code{tinythemes()} logic and should \emph{not} be adjusted manually unless you really know what you are doing or don't mind risking unintended consequences to your plot.
 \item \code{facet.bg}: Character or integer specifying the facet background colour. If an integer, will correspond to the user's default colour palette (see \code{palette}). Passed to \code{rect}. Defaults to \code{NULL} (none).
 \item \code{facet.border}: Character or integer specifying the facet border colour. If an integer, will correspond to the user's default colour palette (see \code{palette}). Passed to \code{rect}. Defaults to \code{NA} (none).
@@ -77,8 +78,8 @@ you should rather use \code{par()} instead.
 \item \code{grid.lwd}: Non-negative numeric giving the line width of the panel grid lines. Defaults to \code{1}.
 \item \code{grid}: Logical indicating whether a background panel grid should be added to plots automatically. Defaults to \code{NULL}, which is equivalent to \code{FALSE}.
 \item \code{lmar}: A numeric vector of form \code{c(inner, outer)} that gives the margin padding, in terms of lines, around the automatic \code{tinyplot} legend. Defaults to \code{c(1.0, 0.1)}. The inner margin is the gap between the legend and the plot region, and the outer margin is the gap between the legend and the edge of the graphics device.
-\item \code{palette.qualitative}: Palette for qualitative colors. See the \code{palette} argumetn in \code{?tinyplot}.
-\item \code{palette.sequential}: Palette for sequential colors. See the \code{palette} argumetn in \code{?tinyplot}.
+\item \code{palette.qualitative}: Palette for qualitative colors. See the \code{palette} argument in \code{?tinyplot}.
+\item \code{palette.sequential}: Palette for sequential colors. See the \code{palette} argument in \code{?tinyplot}.
 \item \code{ribbon.alpha}: Numeric factor in the range \verb{[0,1]} for modifying the opacity alpha of "ribbon" and "area" type plots. Default value is \code{0.2}.
 }
 }
diff --git a/tinyplot.Rproj b/tinyplot.Rproj
index 468aa2fa..dead6016 100644
--- a/tinyplot.Rproj
+++ b/tinyplot.Rproj
@@ -1,5 +1,4 @@
 Version: 1.0
-ProjectId: a8b39023-e69c-4ca8-9eaf-0d4d82596b61
 
 RestoreWorkspace: Default
 SaveWorkspace: Default
