diff --git a/draftlogs/7280_add.md b/draftlogs/7280_add.md
new file mode 100644
index 00000000000..b4a3ecd69d7
--- /dev/null
+++ b/draftlogs/7280_add.md
@@ -0,0 +1 @@
+- Add `pattern.path` attribute as an alternative to the preset `pattern.shape` values, so you can use any SVG path string as a pattern fill. [[#7280](https://github.com/plotly/plotly.js/pull/7280)]
diff --git a/src/components/drawing/attributes.js b/src/components/drawing/attributes.js
index 0d3447c620d..db725070456 100644
--- a/src/components/drawing/attributes.js
+++ b/src/components/drawing/attributes.js
@@ -28,6 +28,16 @@ exports.pattern = {
             'By default, no pattern is used for filling the area.',
         ].join(' ')
     },
+    path: {
+        valType: 'string',
+        arrayOk: true,
+        editType: 'style',
+        description: [
+            'Sets a custom path for pattern fill.',
+            'Use with no `shape` or `solidity`, provide an SVG path string for',
+            'the regions of the square from (0,0) to (`size`,`size`) to color.'
+        ].join(' ')
+    },
     fillmode: {
         valType: 'enumerated',
         values: ['replace', 'overlay'],
diff --git a/src/components/drawing/index.js b/src/components/drawing/index.js
index 5fa39480d6e..3cb3b447eeb 100644
--- a/src/components/drawing/index.js
+++ b/src/components/drawing/index.js
@@ -218,13 +218,14 @@ drawing.dashStyle = function(dash, lineWidth) {
 function setFillStyle(sel, trace, gd, forLegend) {
     var markerPattern = trace.fillpattern;
     var fillgradient = trace.fillgradient;
-    var patternShape = markerPattern && drawing.getPatternAttr(markerPattern.shape, 0, '');
+    var pAttr = drawing.getPatternAttr;
+    var patternShape = markerPattern && (pAttr(markerPattern.shape, 0, '') || pAttr(markerPattern.path, 0, ''));
     if(patternShape) {
-        var patternBGColor = drawing.getPatternAttr(markerPattern.bgcolor, 0, null);
-        var patternFGColor = drawing.getPatternAttr(markerPattern.fgcolor, 0, null);
+        var patternBGColor = pAttr(markerPattern.bgcolor, 0, null);
+        var patternFGColor = pAttr(markerPattern.fgcolor, 0, null);
         var patternFGOpacity = markerPattern.fgopacity;
-        var patternSize = drawing.getPatternAttr(markerPattern.size, 0, 8);
-        var patternSolidity = drawing.getPatternAttr(markerPattern.solidity, 0, 0.3);
+        var patternSize = pAttr(markerPattern.size, 0, 8);
+        var patternSolidity = pAttr(markerPattern.solidity, 0, 0.3);
         var patternID = trace.uid;
         drawing.pattern(sel, 'point', gd, patternID,
             patternShape, patternSize, patternSolidity,
@@ -662,6 +663,16 @@ drawing.pattern = function(sel, calledBy, gd, patternID, shape, size, solidity,
                 fill: fgRGB
             };
             break;
+        default:
+            width = size;
+            height = size;
+            patternTag = 'path';
+            patternAttrs = {
+                d: shape,
+                opacity: opacity,
+                fill: fgRGB
+            };
+            break;
     }
 
     var str = [
@@ -869,7 +880,10 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd, pt) {
         }
 
         var markerPattern = marker.pattern;
-        var patternShape = markerPattern && drawing.getPatternAttr(markerPattern.shape, d.i, '');
+        var pAttr = drawing.getPatternAttr;
+        var patternShape = markerPattern && (
+            pAttr(markerPattern.shape, d.i, '') || pAttr(markerPattern.path, d.i, '')
+        );
 
         if(gradientType && gradientType !== 'none') {
             var gradientColor = d.mgc;
@@ -888,14 +902,15 @@ drawing.singlePointStyle = function(d, sel, trace, fns, gd, pt) {
                 fgcolor = pt.color;
                 perPointPattern = true;
             }
-            var patternFGColor = drawing.getPatternAttr(fgcolor, d.i, (pt && pt.color) || null);
+            var patternFGColor = pAttr(fgcolor, d.i, (pt && pt.color) || null);
 
-            var patternBGColor = drawing.getPatternAttr(markerPattern.bgcolor, d.i, null);
+            var patternBGColor = pAttr(markerPattern.bgcolor, d.i, null);
             var patternFGOpacity = markerPattern.fgopacity;
-            var patternSize = drawing.getPatternAttr(markerPattern.size, d.i, 8);
-            var patternSolidity = drawing.getPatternAttr(markerPattern.solidity, d.i, 0.3);
+            var patternSize = pAttr(markerPattern.size, d.i, 8);
+            var patternSolidity = pAttr(markerPattern.solidity, d.i, 0.3);
             perPointPattern = perPointPattern || d.mcc ||
                 Lib.isArrayOrTypedArray(markerPattern.shape) ||
+                Lib.isArrayOrTypedArray(markerPattern.path) ||
                 Lib.isArrayOrTypedArray(markerPattern.bgcolor) ||
                 Lib.isArrayOrTypedArray(markerPattern.fgcolor) ||
                 Lib.isArrayOrTypedArray(markerPattern.size) ||
diff --git a/src/components/legend/style.js b/src/components/legend/style.js
index f1400698d8b..849271d3962 100644
--- a/src/components/legend/style.js
+++ b/src/components/legend/style.js
@@ -376,11 +376,14 @@ module.exports = function style(s, gd, legend) {
             var fillColor = mcc || d0.mc || marker.color;
 
             var markerPattern = marker.pattern;
-            var patternShape = markerPattern && Drawing.getPatternAttr(markerPattern.shape, 0, '');
+            var pAttr = Drawing.getPatternAttr;
+            var patternShape = markerPattern && (
+                pAttr(markerPattern.shape, 0, '') || pAttr(markerPattern.path, 0, '')
+            );
 
             if(patternShape) {
-                var patternBGColor = Drawing.getPatternAttr(markerPattern.bgcolor, 0, null);
-                var patternFGColor = Drawing.getPatternAttr(markerPattern.fgcolor, 0, null);
+                var patternBGColor = pAttr(markerPattern.bgcolor, 0, null);
+                var patternFGColor = pAttr(markerPattern.fgcolor, 0, null);
                 var patternFGOpacity = markerPattern.fgopacity;
                 var patternSize = dimAttr(markerPattern.size, 8, 10);
                 var patternSolidity = dimAttr(markerPattern.solidity, 0.5, 1);
diff --git a/src/lib/coerce.js b/src/lib/coerce.js
index 7e879b59992..9fa59255bc1 100644
--- a/src/lib/coerce.js
+++ b/src/lib/coerce.js
@@ -502,8 +502,14 @@ exports.coerceFont = function(coerce, attr, dfltObj, opts) {
  */
 exports.coercePattern = function(coerce, attr, markerColor, hasMarkerColorscale) {
     var shape = coerce(attr + '.shape');
-    if(shape) {
-        coerce(attr + '.solidity');
+    var path;
+    if(!shape) {
+        path = coerce(attr + '.path');
+    }
+    if(shape || path) {
+        if(shape) {
+            coerce(attr + '.solidity');
+        }
         coerce(attr + '.size');
         var fillmode = coerce(attr + '.fillmode');
         var isOverlay = fillmode === 'overlay';
diff --git a/src/plot_api/validate.js b/src/plot_api/validate.js
index 45be7d7bbc4..8119eb4a627 100644
--- a/src/plot_api/validate.js
+++ b/src/plot_api/validate.js
@@ -214,7 +214,11 @@ function crawl(objIn, objOut, schema, list, base, path) {
         } else if(!Lib.validate(valIn, nestedSchema)) {
             list.push(format('value', base, p, valIn));
         } else if(nestedSchema.valType === 'enumerated' &&
-            ((nestedSchema.coerceNumber && valIn !== +valOut) || valIn !== valOut)
+            (
+                (nestedSchema.coerceNumber && valIn !== +valOut) ||
+                (!isArrayOrTypedArray(valIn) && valIn !== valOut) ||
+                (String(valIn) !== String(valOut))
+            )
         ) {
             list.push(format('dynamic', base, p, valIn, valOut));
         }
diff --git a/test/image/baselines/zz-pattern_bars-path.png b/test/image/baselines/zz-pattern_bars-path.png
new file mode 100644
index 00000000000..cff51494b5b
Binary files /dev/null and b/test/image/baselines/zz-pattern_bars-path.png differ
diff --git a/test/image/mocks/zz-pattern_bars-path.json b/test/image/mocks/zz-pattern_bars-path.json
new file mode 100644
index 00000000000..13e554ed4c3
--- /dev/null
+++ b/test/image/mocks/zz-pattern_bars-path.json
@@ -0,0 +1,218 @@
+{
+ "data": [
+  {
+   "x": ["a", "b", "c", "d", "e"],
+   "y": [1, 2, 3, 4, 5],
+   "name": "Bar 1",
+   "type": "bar",
+   "textposition": "outside",
+   "text": "bgcolor",
+   "marker": {
+    "pattern": {
+     "shape": "/",
+     "bgcolor": ["", "lightblue", "blue", "darkblue", "black"]
+    }
+   }
+  },
+  {
+   "x": ["a", "b", "c", "d", "e"],
+   "y": [2, 3, 4, 5, 6],
+   "name": "Bar 2",
+   "type": "bar",
+   "textposition": "outside",
+   "text": "shape",
+   "marker": {
+    "pattern": {
+     "shape": ["|", "/", "-", "\\", "|"]
+    }
+   }
+  },
+  {
+   "x": ["a", "b", "c", "d", "e"],
+   "y": [3, 4, 5, 6, 7],
+   "name": "Bar 3",
+   "type": "bar",
+   "textposition": "outside",
+   "text": "size",
+   "marker": {
+    "pattern": {
+     "shape": "x",
+     "size": [4, 6, 8, 10, 12]
+    }
+   }
+  },
+  {
+   "x": ["a", "b", "c", "d", "e"],
+   "y": [6, 7, 8, 9, 10],
+   "name": "Bar 4",
+   "type": "bar",
+   "textposition": "outside",
+   "text": "solidity",
+   "marker": {
+    "pattern": {
+     "shape": ".",
+     "bgcolor": "yellow",
+     "solidity": [0.1, 0.3, 0.5, 0.7, 0.9]
+    }
+   }
+  },
+  {
+    "x": ["a", "b", "c", "d", "e"],
+    "y": [7, 8, 9, 10, 11],
+    "name": "Bar 5",
+    "type": "bar",
+    "textposition": "outside",
+    "text": "path",
+    "marker": {
+     "pattern": {
+      "path": [
+        "M0,0H4V4H0Z",
+        "M0,0H6V6Z",
+        "M0,0V4H4Z",
+        "M0,0C0,2,4,2,4,4C4,6,0,6,0,8H2C2,6,6,6,6,4C6,2,2,2,2,0Z",
+        "M4,4L7,2A3.5,3.5,0,1,0,7,6Z"
+      ],
+      "fgcolor": "yellow",
+      "bgcolor": "black"
+     }
+    }
+   },
+  {
+   "r": [1, 2, 3, 4],
+   "type": "barpolar",
+   "name": "Barpolar 1",
+   "marker": {
+    "color": "red",
+    "pattern": {
+     "shape": "+",
+     "size": [1, 2, 3, 4]
+    }
+   }
+  },
+  {
+   "r": [2, 3, 4, 1],
+   "type": "barpolar",
+   "name": "Barpolar 2",
+   "marker": {
+    "color": "rgba(0,127,0,0.5)",
+    "pattern": {
+     "shape": "x",
+     "solidity": 0.75
+    }
+   }
+  },
+  {
+   "r": [3, 4, 1, 2],
+   "type": "barpolar",
+   "name": "Barpolar 3",
+   "marker": {
+    "color": "blue",
+    "pattern": {
+     "shape": ["|", "-", "|", "-"],
+     "solidity": 0.5
+    }
+   }
+  },
+  {
+   "r": [4, 1, 2, 3],
+   "type": "barpolar",
+   "name": "Barpolar 4",
+   "marker": {
+    "color": "orange",
+    "pattern": {
+     "shape": ".",
+     "bgcolor": "yellow",
+     "solidity": [0.2, 0.8, 0.6, 0.4]
+    }
+   }
+  },
+
+  {
+   "xaxis": "x2",
+   "yaxis": "y2",
+   "y": ["A", "A", "A", "A", "B", "B", "C"],
+   "name": "Histogram 1",
+   "type": "histogram",
+   "marker": {
+    "color": "yellow",
+    "line": {
+     "color": "black",
+     "width": 2
+    },
+    "pattern": {
+     "bgcolor": "blue",
+     "shape": "."
+    }
+   }
+  },
+  {
+   "xaxis": "x2",
+   "yaxis": "y2",
+   "y": ["C", "C", "C", "C", "B", "B", "A"],
+   "name": "Histogram 2",
+   "type": "histogram",
+   "marker": {
+    "color": "yellow",
+    "line": {
+     "color": "red",
+     "width": 4
+    },
+    "pattern": {
+     "bgcolor": "rgba(255, 127,0,0.5)",
+     "shape": "x"
+    }
+   }
+  },
+
+  {
+   "xaxis": "x3",
+   "yaxis": "y3",
+   "x": [3, 2, 1],
+   "y": ["U", "V", "W"],
+   "name": "Funnel",
+   "type": "funnel"
+  }
+ ],
+ "layout": {
+  "title": {
+   "text": "pattern options"
+  },
+  "width": 1000,
+  "height": 600,
+
+  "xaxis": {
+   "domain": [0, 1]
+  },
+  "yaxis": {
+   "range": [0, 11],
+   "domain": [0, 0.475]
+  },
+
+  "polar": {
+   "domain": {
+    "x": [0.35, 0.65],
+    "y": [0.525, 1]
+   }
+  },
+
+  "xaxis2": {
+   "anchor": "y2",
+   "gridcolor": "black",
+   "gridwidth": 2,
+   "domain": [0, 0.3]
+  },
+  "yaxis2": {
+   "anchor": "x2",
+   "domain": [0.525, 1]
+  },
+
+  "xaxis3": {
+   "anchor": "y3",
+   "domain": [0.7, 1]
+  },
+  "yaxis3": {
+   "anchor": "x3",
+   "domain": [0.525, 1]
+  }
+ }
+}
diff --git a/test/plot-schema.json b/test/plot-schema.json
index 6aa77cf3338..dc18446a37e 100644
--- a/test/plot-schema.json
+++ b/test/plot-schema.json
@@ -17808,6 +17808,17 @@
         "overlay"
        ]
       },
+      "path": {
+       "arrayOk": true,
+       "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+       "editType": "style",
+       "valType": "string"
+      },
+      "pathsrc": {
+       "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+       "editType": "none",
+       "valType": "string"
+      },
       "role": "object",
       "shape": {
        "arrayOk": true,
@@ -19835,6 +19846,17 @@
         "overlay"
        ]
       },
+      "path": {
+       "arrayOk": true,
+       "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+       "editType": "style",
+       "valType": "string"
+      },
+      "pathsrc": {
+       "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+       "editType": "none",
+       "valType": "string"
+      },
       "role": "object",
       "shape": {
        "arrayOk": true,
@@ -37562,6 +37584,17 @@
         "overlay"
        ]
       },
+      "path": {
+       "arrayOk": true,
+       "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+       "editType": "style",
+       "valType": "string"
+      },
+      "pathsrc": {
+       "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+       "editType": "none",
+       "valType": "string"
+      },
       "role": "object",
       "shape": {
        "arrayOk": true,
@@ -41225,6 +41258,17 @@
         "overlay"
        ]
       },
+      "path": {
+       "arrayOk": true,
+       "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+       "editType": "style",
+       "valType": "string"
+      },
+      "pathsrc": {
+       "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+       "editType": "none",
+       "valType": "string"
+      },
       "role": "object",
       "shape": {
        "arrayOk": true,
@@ -46456,6 +46500,17 @@
         "overlay"
        ]
       },
+      "path": {
+       "arrayOk": true,
+       "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+       "editType": "style",
+       "valType": "string"
+      },
+      "pathsrc": {
+       "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+       "editType": "none",
+       "valType": "string"
+      },
       "role": "object",
       "shape": {
        "arrayOk": true,
@@ -56226,6 +56281,17 @@
         "overlay"
        ]
       },
+      "path": {
+       "arrayOk": true,
+       "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+       "editType": "style",
+       "valType": "string"
+      },
+      "pathsrc": {
+       "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+       "editType": "none",
+       "valType": "string"
+      },
       "role": "object",
       "shape": {
        "arrayOk": true,
@@ -58612,6 +58678,17 @@
        "overlay"
       ]
      },
+     "path": {
+      "arrayOk": true,
+      "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+      "editType": "style",
+      "valType": "string"
+     },
+     "pathsrc": {
+      "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+      "editType": "none",
+      "valType": "string"
+     },
      "role": "object",
      "shape": {
       "arrayOk": true,
@@ -87705,6 +87782,17 @@
         "overlay"
        ]
       },
+      "path": {
+       "arrayOk": true,
+       "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+       "editType": "style",
+       "valType": "string"
+      },
+      "pathsrc": {
+       "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+       "editType": "none",
+       "valType": "string"
+      },
       "role": "object",
       "shape": {
        "arrayOk": true,
@@ -92346,6 +92434,17 @@
         "overlay"
        ]
       },
+      "path": {
+       "arrayOk": true,
+       "description": "Sets a custom path for pattern fill. Use with no `shape` or `solidity`, provide an SVG path string for the regions of the square from (0,0) to (`size`,`size`) to color.",
+       "editType": "style",
+       "valType": "string"
+      },
+      "pathsrc": {
+       "description": "Sets the source reference on Chart Studio Cloud for `path`.",
+       "editType": "none",
+       "valType": "string"
+      },
       "role": "object",
       "shape": {
        "arrayOk": true,