diff --git a/docs/features/marks.md b/docs/features/marks.md
index 99f805f0a6..da319afdb0 100644
--- a/docs/features/marks.md
+++ b/docs/features/marks.md
@@ -482,6 +482,7 @@ All marks support the following style options:
* **dx** - horizontal offset (in pixels; defaults to 0)
* **dy** - vertical offset (in pixels; defaults to 0)
* **target** - link target (e.g., “_blank” for a new window); for use with the **href** channel
+* **className** - the [class attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class), if any (defaults to null)
* **ariaDescription** - a textual description of the mark’s contents
* **ariaHidden** - if true, hide this content from the accessibility tree
* **pointerEvents** - the [pointer events](https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events) (*e.g.*, *none*)
diff --git a/src/mark.d.ts b/src/mark.d.ts
index 54f14276ca..d244fdba76 100644
--- a/src/mark.d.ts
+++ b/src/mark.d.ts
@@ -239,6 +239,13 @@ export interface MarkOptions {
*/
marginLeft?: number;
+ /**
+ * The [class attribute][1]; a constant string.
+ *
+ * [1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class
+ */
+ className?: string;
+
/**
* The [aria-description][1]; a constant textual description.
*
diff --git a/src/mark.js b/src/mark.js
index 768105025e..c8c3bca719 100644
--- a/src/mark.js
+++ b/src/mark.js
@@ -4,7 +4,7 @@ import {maybeFacetAnchor} from "./facet.js";
import {maybeClip, maybeNamed, maybeValue} from "./options.js";
import {arrayify, isDomainSort, isObject, isOptions, keyword, range, singleton} from "./options.js";
import {project} from "./projection.js";
-import {styles} from "./style.js";
+import {maybeClassName, styles} from "./style.js";
import {basic, initializer} from "./transforms/basic.js";
export class Mark {
@@ -22,6 +22,7 @@ export class Mark {
marginRight = margin,
marginBottom = margin,
marginLeft = margin,
+ className,
clip = defaults?.clip,
channels: extraChannels,
tip,
@@ -71,6 +72,7 @@ export class Mark {
this.marginLeft = +marginLeft;
this.clip = maybeClip(clip);
this.tip = maybeTip(tip);
+ this.className = className ? maybeClassName(className) : null;
// Super-faceting currently disallow position channels; in the future, we
// could allow position to be specified in fx and fy in addition to (or
// instead of) x and y.
diff --git a/src/style.js b/src/style.js
index a1af100fcd..53601f3f62 100644
--- a/src/style.js
+++ b/src/style.js
@@ -348,6 +348,7 @@ function applyClip(selection, mark, dimensions, context) {
// Note: may mutate selection.node!
export function applyIndirectStyles(selection, mark, dimensions, context) {
applyClip(selection, mark, dimensions, context);
+ applyAttr(selection, "class", mark.className);
applyAttr(selection, "fill", mark.fill);
applyAttr(selection, "fill-opacity", mark.fillOpacity);
applyAttr(selection, "stroke", mark.stroke);
diff --git a/test/output/classNameOnMarks.svg b/test/output/classNameOnMarks.svg
new file mode 100644
index 0000000000..d06c154f19
--- /dev/null
+++ b/test/output/classNameOnMarks.svg
@@ -0,0 +1,66 @@
+
\ No newline at end of file
diff --git a/test/plots/class-name.ts b/test/plots/class-name.ts
new file mode 100644
index 0000000000..df37884502
--- /dev/null
+++ b/test/plots/class-name.ts
@@ -0,0 +1,20 @@
+import * as Plot from "@observablehq/plot";
+import * as d3 from "d3";
+
+export async function classNameOnMarks() {
+ const sales = await d3.csv("data/fruit-sales.csv", d3.autoType);
+ return Plot.plot({
+ marginLeft: 50,
+ y: {
+ label: null,
+ reverse: true
+ },
+ marks: [
+ Plot.barX(
+ sales,
+ Plot.groupY({x: "sum"}, {x: "units", y: "fruit", sort: {y: "x", reverse: true}, className: "fruitbars"})
+ ),
+ Plot.ruleX([0])
+ ]
+ });
+}
diff --git a/test/plots/index.ts b/test/plots/index.ts
index f1b253323e..7b99e1ada1 100644
--- a/test/plots/index.ts
+++ b/test/plots/index.ts
@@ -51,6 +51,7 @@ export * from "./cars-mpg.js";
export * from "./cars-parcoords.js";
export * from "./channel-domain.js";
export * from "./clamp.js";
+export * from "./class-name.js";
export * from "./collapsed-histogram.js";
export * from "./color-piecewise.js";
export * from "./country-centroids.js";