diff --git a/NEWS.md b/NEWS.md
index b132c706..23a41c3f 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -14,6 +14,7 @@ New features:
   support, first raised in #2, so that a boxplot is automatically plotted if a
   numeric is plotted against a factor. (#154 @grantmcdermott)
   - `type = "polypath`. (#159 @grantmcdermott)
+  - `type = "rect"`. (#161 @grantmcdermott)
 
 Misc:
 
diff --git a/R/draw_legend.R b/R/draw_legend.R
index 3ef30768..b1b914c9 100644
--- a/R/draw_legend.R
+++ b/R/draw_legend.R
@@ -166,10 +166,10 @@ draw_legend = function(
   ) {
     legend_args[["pt.cex"]] = cex
   }
-  if (type %in% c("ribbon", "polygon", "polypath", "boxplot") || isTRUE(gradient)) {
+  if (type %in% c("rect", "ribbon", "polygon", "polypath", "boxplot") || isTRUE(gradient)) {
     legend_args[["pch"]] = 22
     if (is.null(legend_args[["pt.cex"]])) legend_args[["pt.cex"]] = 3.5
-    if (is.null(legend_args[["pt.lwd"]]) && (!is.null(type) && !(type %in% c("polygon", "polypath", "boxplot")))) {
+    if (is.null(legend_args[["pt.lwd"]]) && (!is.null(type) && !(type %in% c("rect", "polygon", "polypath", "boxplot")))) {
       legend_args[["pt.lwd"]] = 0
     }
     if (is.null(legend_args[["y.intersp"]])) legend_args[["y.intersp"]] = 1.25
diff --git a/R/tinyplot.R b/R/tinyplot.R
index a4819bfd..5a780409 100644
--- a/R/tinyplot.R
+++ b/R/tinyplot.R
@@ -208,9 +208,9 @@
 #'   longer discussion about the trade-offs involved.
 #' @param subset,na.action,drop.unused.levels arguments passed to `model.frame`
 #'   when extracting the data from `formula` and `data`.
-#' @param ymin,ymax minimum and maximum coordinates of interval plot types. Only
-#'   used when the `type` argument is one of "pointrange", "errorbar", or
-#'   "ribbon".
+#' @param xmin,xmax,ymin,ymax minimum and maximum coordinates of relevant area
+#'   or interval plot types. Only used when the `type` argument is one of
+#'   "pointrange", "errorbar", "ribbon", or "rect".
 #' @param ribbon.alpha numeric factor modifying the opacity alpha of any ribbon
 #'   shading; typically in `[0, 1]`. Only used when `type = "ribbon"`, or when
 #'   the `bg` fill argument is specified in a density plot (since filled density
@@ -478,6 +478,8 @@ tinyplot.default = function(
     alpha = NULL,
     cex = 1,
     restore.par = FALSE,
+    xmin = NULL,
+    xmax = NULL,
     ymin = NULL,
     ymax = NULL,
     ribbon.alpha = NULL,
@@ -558,7 +560,12 @@ tinyplot.default = function(
   )
   
   # Capture deparsed expressions early, before x, y and by are evaluated
-  x_dep = deparse1(substitute(x))
+  x_dep = if (!missing(x)) {
+    deparse1(substitute(x)) 
+  } else if (type == "rect") {
+    x = NULL
+    NULL
+  }
   y_dep = if (is.null(y)) {
     deparse1(substitute(x))
   } else {
@@ -579,7 +586,7 @@ tinyplot.default = function(
   }
   
   # enforce boxplot type for y ~ factor(x)
-  if (is.factor(x) && !is.factor(y)) {
+  if (!is.null(x) && is.factor(x) && !is.factor(y)) {
     type = "boxplot"
   }
 
@@ -616,9 +623,19 @@ tinyplot.default = function(
     return(do.call(tinyplot.density, args = fargs))
   }
   
+  if (is.null(x)) {
+    ## Special catch for area plots without a specified y-var
+    if (type %in% c("rect")) {
+      xmin_dep = deparse(substitute(xmin))
+      xmax_dep = deparse(substitute(xmax))
+      x_dep = paste0("[", xmin_dep, ", ", xmax_dep, "]")
+      x = rep(NA, length(x))
+      if (is.null(xlim)) xlim = range(c(xmin, xmax))
+    }
+  } 
   if (is.null(y)) {
-    ## Special catch for interval plots without a specified y-var
-    if (type %in% c("pointrange", "errorbar", "ribbon")) {
+    ## Special catch for area and interval plots without a specified y-var
+    if (type %in% c("rect", "pointrange", "errorbar", "ribbon")) {
       ymin_dep = deparse(substitute(ymin))
       ymax_dep = deparse(substitute(ymax))
       y_dep = paste0("[", ymin_dep, ", ", ymax_dep, "]")
@@ -689,6 +706,8 @@ tinyplot.default = function(
   if (is.null(xlim)) xlim = range(xy$x[is.finite(xy$x)])
   if (is.null(ylim)) ylim = range(xy$y[is.finite(xy$y)])
 
+  if (!is.null(xmin)) xlim[1] = min(c(xlim, xmin))
+  if (!is.null(xmax)) xlim[2] = max(c(xlim, xmax))
   if (!is.null(ymin)) ylim[1] = min(c(ylim, ymin))
   if (!is.null(ymax)) ylim[2] = max(c(ylim, ymax))
 
@@ -714,13 +733,20 @@ tinyplot.default = function(
   
   if (!is.null(by) && !by_continuous) {
     split_data = list(x=x, y=y)
+    split_data[["xmin"]] = xmin
+    split_data[["xmax"]] = xmax
     split_data[["ymin"]] = ymin
     split_data[["ymax"]] = ymax
     split_data[["facet"]] = facet
     split_data = lapply(split_data, split, by)
     split_data = do.call(function(...) Map("list", ...), split_data)
   } else {
-    split_data = list(list(x=x, y=y, ymin=ymin, ymax=ymax, facet=facet))
+    split_data = list(list(
+      x = x, y = y,
+      xmin = xmin, xmax = xmax,
+      ymin = ymin, ymax = ymax,
+      facet = facet
+    ))
   }
   
   ngrps = length(split_data)
@@ -1285,6 +1311,8 @@ tinyplot.default = function(
       ## Need extra catch for non-groupby data that also doesn't have ymin or
       ## ymax vars
       if (is.null(by) || isTRUE(by_continuous)) {
+        if (is.null(idata[["xmin"]])) idata[["xmin"]] = NULL
+        if (is.null(idata[["xmax"]])) idata[["xmax"]] = NULL
         if (is.null(idata[["ymin"]])) idata[["ymin"]] = NULL
         if (is.null(idata[["ymax"]])) idata[["ymax"]] = NULL
       }
@@ -1320,6 +1348,8 @@ tinyplot.default = function(
     for (ii in seq_along(idata)) {
       xx = idata[[ii]]$x
       yy = idata[[ii]]$y
+      xxmin = idata[[ii]]$xmin
+      xxmax = idata[[ii]]$xmax
       yymin = idata[[ii]]$ymin
       yymax = idata[[ii]]$ymax
       
@@ -1340,7 +1370,7 @@ tinyplot.default = function(
       
       # empty plot flag
       empty_plot = FALSE
-      if (type=="n" || length(xx)==0) {
+      if (type=="n" || ((length(xx)==0) && type!="rect")) {
         empty_plot = TRUE
       }
       
@@ -1454,6 +1484,13 @@ tinyplot.default = function(
           staplewex = staplewex_xx,
           outwex = outwex_xx
         )
+      } else if (type == "rect") {
+        rect(
+          xleft = xxmin, ybottom = yymin, xright = xxmax, ytop = yymax,
+          lty = ilty,
+          border = icol,
+          col =  ibg
+        )
       } else {
         stop("`type` argument not supported.", call. = FALSE)
       }
diff --git a/inst/tinytest/_tinysnapshot/rect_by_fill.svg b/inst/tinytest/_tinysnapshot/rect_by_fill.svg
new file mode 100644
index 00000000..ac564ad1
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/rect_by_fill.svg
@@ -0,0 +1,93 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<image width='18.00' height='86.40' x='465.09' y='205.84' preserveAspectRatio='none' xlink:href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABkCAYAAABHLFpgAAAAjElEQVQYlXWKsXHEQAzEQPDkwD24Ilf3Dd86kHSW9PMJB8CS359X3FI8zwg4dvqgncLBOTRgBxwsheOlC+yqRWBXTvJsCrb/Q67tQp3Vcm1vOo9mP2i+EWNi9cQaE7lQjoH7umtnae7tMQSRpTeKtVodf+lCWsTCtIdGke47DUw3stPAuCG9YfzC6Td/l79JGkcdgJAAAAAASUVORK5CYII='/>
+<text x='483.09' y='296.37' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='10.01px' lengthAdjust='spacingAndGlyphs'> 0</text>
+<text x='483.09' y='274.55' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'> 10</text>
+<text x='483.09' y='253.61' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'> 20</text>
+<text x='483.09' y='231.79' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'> 30</text>
+<text x='483.09' y='209.97' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='16.68px' lengthAdjust='spacingAndGlyphs'> 40</text>
+<text x='483.09' y='296.37' text-anchor='end' style='font-size: 12.00px;fill: #FFFFFF; font-family: "Liberation Sans";' textLength='17.99px' lengthAdjust='spacingAndGlyphs'>-   -</text>
+<text x='483.09' y='274.55' text-anchor='end' style='font-size: 12.00px;fill: #FFFFFF; font-family: "Liberation Sans";' textLength='17.99px' lengthAdjust='spacingAndGlyphs'>-   -</text>
+<text x='483.09' y='253.61' text-anchor='end' style='font-size: 12.00px;fill: #FFFFFF; font-family: "Liberation Sans";' textLength='17.99px' lengthAdjust='spacingAndGlyphs'>-   -</text>
+<text x='483.09' y='231.79' text-anchor='end' style='font-size: 12.00px;fill: #FFFFFF; font-family: "Liberation Sans";' textLength='17.99px' lengthAdjust='spacingAndGlyphs'>-   -</text>
+<text x='483.09' y='209.97' text-anchor='end' style='font-size: 12.00px;fill: #FFFFFF; font-family: "Liberation Sans";' textLength='17.99px' lengthAdjust='spacingAndGlyphs'>-   -</text>
+<text x='465.09' y='191.44' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='2.66px' lengthAdjust='spacingAndGlyphs'>i</text>
+</g>
+<defs>
+  <clipPath id='cpMC4wMHw0NDcuODF8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='447.81' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw0NDcuODF8MC4wMHw1MDQuMDA=)'>
+<text x='253.43' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='86.07px' lengthAdjust='spacingAndGlyphs'>[100 + i, 150 + i]</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='86.07px' lengthAdjust='spacingAndGlyphs'>[300 + i, 380 + i]</text>
+</g>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<line x1='73.44' y1='430.56' x2='393.42' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='73.44' y1='430.56' x2='73.44' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='153.43' y1='430.56' x2='153.43' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='233.43' y1='430.56' x2='233.43' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='313.42' y1='430.56' x2='313.42' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='393.42' y1='430.56' x2='393.42' y2='437.76' style='stroke-width: 0.75;' />
+<text x='73.44' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>100</text>
+<text x='153.43' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>120</text>
+<text x='233.43' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>140</text>
+<text x='313.42' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>160</text>
+<text x='393.42' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>180</text>
+<line x1='59.04' y1='416.80' x2='59.04' y2='72.80' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='416.80' x2='51.84' y2='416.80' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='359.47' x2='51.84' y2='359.47' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='302.13' x2='51.84' y2='302.13' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='244.80' x2='51.84' y2='244.80' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='187.47' x2='51.84' y2='187.47' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='130.13' x2='51.84' y2='130.13' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='72.80' x2='51.84' y2='72.80' style='stroke-width: 0.75;' />
+<text transform='translate(41.76,416.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>300</text>
+<text transform='translate(41.76,359.47) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>320</text>
+<text transform='translate(41.76,302.13) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>340</text>
+<text transform='translate(41.76,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>360</text>
+<text transform='translate(41.76,187.47) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>380</text>
+<text transform='translate(41.76,130.13) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>400</text>
+<text transform='translate(41.76,72.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>420</text>
+<polygon points='59.04,430.56 447.81,430.56 447.81,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDQ3LjgxfDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='388.77' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDQ3LjgxfDU5LjA0fDQzMC41Ng==)'>
+<rect x='73.44' y='187.47' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #E7D39A; fill: #E7D39A; fill-opacity: 0.20;' />
+<rect x='89.44' y='176.00' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #EFBB6C; fill: #EFBB6C; fill-opacity: 0.20;' />
+<rect x='105.44' y='164.53' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #F2A05E; fill: #F2A05E; fill-opacity: 0.20;' />
+<rect x='121.44' y='153.07' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #F38464; fill: #F38464; fill-opacity: 0.20;' />
+<rect x='137.43' y='141.60' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #EF6575; fill: #EF6575; fill-opacity: 0.20;' />
+<rect x='153.43' y='130.13' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #E64886; fill: #E64886; fill-opacity: 0.20;' />
+<rect x='169.43' y='118.67' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #D13094; fill: #D13094; fill-opacity: 0.20;' />
+<rect x='185.43' y='107.20' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #B71C9B; fill: #B71C9B; fill-opacity: 0.20;' />
+<rect x='201.43' y='95.73' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #9A0F9C; fill: #9A0F9C; fill-opacity: 0.20;' />
+<rect x='217.43' y='84.27' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #771399; fill: #771399; fill-opacity: 0.20;' />
+<rect x='233.43' y='72.80' width='199.99' height='229.33' style='stroke-width: 0.75; stroke: #4B1D91; fill: #4B1D91; fill-opacity: 0.20;' />
+</g>
+</svg>
diff --git a/inst/tinytest/_tinysnapshot/rect_simple.svg b/inst/tinytest/_tinysnapshot/rect_simple.svg
new file mode 100644
index 00000000..d3b22fb2
--- /dev/null
+++ b/inst/tinytest/_tinysnapshot/rect_simple.svg
@@ -0,0 +1,72 @@
+<?xml version='1.0' encoding='UTF-8' ?>
+<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' class='svglite' width='504.00pt' height='504.00pt' viewBox='0 0 504.00 504.00'>
+<defs>
+  <style type='text/css'><![CDATA[
+    .svglite line, .svglite polyline, .svglite polygon, .svglite path, .svglite rect, .svglite circle {
+      fill: none;
+      stroke: #000000;
+      stroke-linecap: round;
+      stroke-linejoin: round;
+      stroke-miterlimit: 10.00;
+    }
+    .svglite text {
+      white-space: pre;
+    }
+  ]]></style>
+</defs>
+<rect width='100%' height='100%' style='stroke: none; fill: #FFFFFF;'/>
+<defs>
+  <clipPath id='cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA='>
+    <rect x='0.00' y='0.00' width='504.00' height='504.00' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpMC4wMHw1MDQuMDB8MC4wMHw1MDQuMDA=)'>
+<text x='266.40' y='485.28' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='86.07px' lengthAdjust='spacingAndGlyphs'>[100 + i, 150 + i]</text>
+<text transform='translate(12.96,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='86.07px' lengthAdjust='spacingAndGlyphs'>[300 + i, 380 + i]</text>
+<line x1='74.40' y1='430.56' x2='415.73' y2='430.56' style='stroke-width: 0.75;' />
+<line x1='74.40' y1='430.56' x2='74.40' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='159.73' y1='430.56' x2='159.73' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='245.07' y1='430.56' x2='245.07' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='330.40' y1='430.56' x2='330.40' y2='437.76' style='stroke-width: 0.75;' />
+<line x1='415.73' y1='430.56' x2='415.73' y2='437.76' style='stroke-width: 0.75;' />
+<text x='74.40' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>100</text>
+<text x='159.73' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>120</text>
+<text x='245.07' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>140</text>
+<text x='330.40' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>160</text>
+<text x='415.73' y='456.48' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>180</text>
+<line x1='59.04' y1='416.80' x2='59.04' y2='72.80' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='416.80' x2='51.84' y2='416.80' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='359.47' x2='51.84' y2='359.47' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='302.13' x2='51.84' y2='302.13' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='244.80' x2='51.84' y2='244.80' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='187.47' x2='51.84' y2='187.47' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='130.13' x2='51.84' y2='130.13' style='stroke-width: 0.75;' />
+<line x1='59.04' y1='72.80' x2='51.84' y2='72.80' style='stroke-width: 0.75;' />
+<text transform='translate(41.76,416.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>300</text>
+<text transform='translate(41.76,359.47) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>320</text>
+<text transform='translate(41.76,302.13) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>340</text>
+<text transform='translate(41.76,244.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>360</text>
+<text transform='translate(41.76,187.47) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>380</text>
+<text transform='translate(41.76,130.13) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>400</text>
+<text transform='translate(41.76,72.80) rotate(-90)' text-anchor='middle' style='font-size: 12.00px; font-family: "Liberation Sans";' textLength='20.02px' lengthAdjust='spacingAndGlyphs'>420</text>
+<polygon points='59.04,430.56 473.76,430.56 473.76,59.04 59.04,59.04 ' style='stroke-width: 0.75;' />
+</g>
+<defs>
+  <clipPath id='cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng=='>
+    <rect x='59.04' y='59.04' width='414.72' height='371.52' />
+  </clipPath>
+</defs>
+<g clip-path='url(#cpNTkuMDR8NDczLjc2fDU5LjA0fDQzMC41Ng==)'>
+<rect x='74.40' y='187.47' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='91.47' y='176.00' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='108.53' y='164.53' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='125.60' y='153.07' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='142.67' y='141.60' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='159.73' y='130.13' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='176.80' y='118.67' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='193.87' y='107.20' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='210.93' y='95.73' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='228.00' y='84.27' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+<rect x='245.07' y='72.80' width='213.33' height='229.33' style='stroke-width: 0.75;' />
+</g>
+</svg>
diff --git a/inst/tinytest/test-rect.R b/inst/tinytest/test-rect.R
new file mode 100644
index 00000000..1ac863fd
--- /dev/null
+++ b/inst/tinytest/test-rect.R
@@ -0,0 +1,30 @@
+source("helpers.R")
+using("tinysnapshot")
+
+f = function() {
+  i = 4*(0:10)
+  plt(
+    xmin = 100+i,
+    ymin = 300+i,
+    xmax = 150+i,
+    ymax = 380+i,
+    type = "rect"
+  )
+}
+expect_snapshot_plot(f, label = "rect_simple")
+
+f = function() {
+  i = 4*(0:10)
+  plt(
+    xmin = 100+i,
+    ymin = 300+i,
+    xmax = 150+i,
+    ymax = 380+i,
+    by = i,
+    type = "rect",
+    fill = 0.2,
+    palette = "agsunset"
+  )
+}
+expect_snapshot_plot(f, label = "rect_by_fill")
+
diff --git a/man/tinyplot.Rd b/man/tinyplot.Rd
index c0f0eebe..40580493 100644
--- a/man/tinyplot.Rd
+++ b/man/tinyplot.Rd
@@ -41,6 +41,8 @@ tinyplot(x, ...)
   alpha = NULL,
   cex = 1,
   restore.par = FALSE,
+  xmin = NULL,
+  xmax = NULL,
   ymin = NULL,
   ymax = NULL,
   ribbon.alpha = NULL,
@@ -349,9 +351,9 @@ setting to TRUE instead. See also \link{get_saved_par} for another option to
 recover the original \code{\link[graphics]{par}} settings, as well as
 longer discussion about the trade-offs involved.}
 
-\item{ymin, ymax}{minimum and maximum coordinates of interval plot types. Only
-used when the \code{type} argument is one of "pointrange", "errorbar", or
-"ribbon".}
+\item{xmin, xmax, ymin, ymax}{minimum and maximum coordinates of relevant area
+or interval plot types. Only used when the \code{type} argument is one of
+"pointrange", "errorbar", "ribbon", or "rect".}
 
 \item{ribbon.alpha}{numeric factor modifying the opacity alpha of any ribbon
 shading; typically in \verb{[0, 1]}. Only used when \code{type = "ribbon"}, or when
