diff --git a/draftlogs/6989_fix.md b/draftlogs/6989_fix.md
new file mode 100644
index 00000000000..7e28efa12c9
--- /dev/null
+++ b/draftlogs/6989_fix.md
@@ -0,0 +1 @@
+ - Add support for xref and yref "paper" for shapes with layer "between" [[#6989](https://github.com/plotly/plotly.js/pull/6989)]
\ No newline at end of file
diff --git a/src/components/rangeslider/draw.js b/src/components/rangeslider/draw.js
index 3f9049070e8..da87679683e 100644
--- a/src/components/rangeslider/draw.js
+++ b/src/components/rangeslider/draw.js
@@ -504,7 +504,7 @@ function drawRangePlot(rangeSlider, gd, axisOpts, opts) {
 
         var plotinfo = {
             id: id,
-            plotgroup: plotgroup,
+            plotgroup: [undefined, plotgroup], // ragenslider has no background layer
             xaxis: xa,
             yaxis: ya,
             isRangePlot: true
diff --git a/src/components/shapes/draw.js b/src/components/shapes/draw.js
index 4cc75dc920e..a6a74b6901a 100644
--- a/src/components/shapes/draw.js
+++ b/src/components/shapes/draw.js
@@ -93,10 +93,10 @@ function drawOne(gd, index) {
 
     if(options.layer === 'above') {
         drawShape(gd._fullLayout._shapeUpperLayer);
+    } else if(options.layer === 'between') {
+        drawShape(gd._fullLayout._shapeLayerBetween);
     } else if(options.xref === 'paper' || options.yref === 'paper') {
         drawShape(gd._fullLayout._shapeLowerLayer);
-    } else if(options.layer === 'between') {
-        drawShape(plotinfo.shapelayerBetween);
     } else {
         if(plotinfo._hadPlotinfo) {
             var mainPlot = plotinfo.mainplotinfo || plotinfo;
diff --git a/src/plot_api/plot_api.js b/src/plot_api/plot_api.js
index 39f9bc93496..7cb790b5c37 100644
--- a/src/plot_api/plot_api.js
+++ b/src/plot_api/plot_api.js
@@ -3731,8 +3731,11 @@ function makePlotFramework(gd) {
         .classed('shapelayer', true);
 
     // single cartesian layer for the whole plot
-    fullLayout._cartesianlayer = fullLayout._paper.append('g').classed('cartesianlayer', true);
-
+    fullLayout._cartesianlayerBelow = fullLayout._paper.append('g').classed('cartesianlayer-below', true);
+    var layerBetween = fullLayout._paper.append('g').classed('layer-between', true);
+    fullLayout._imageLayerBetween = layerBetween.append('g').classed('imagelayer', true);
+    fullLayout._shapeLayerBetween = layerBetween.append('g').classed('shapelayer', true);
+    fullLayout._cartesianlayerAbove = fullLayout._paper.append('g').classed('cartesianlayer', true);
     // single polar layer for the whole plot
     fullLayout._polarlayer = fullLayout._paper.append('g').classed('polarlayer', true);
 
diff --git a/src/plot_api/subroutines.js b/src/plot_api/subroutines.js
index cd5e890d01c..2c885c872d9 100644
--- a/src/plot_api/subroutines.js
+++ b/src/plot_api/subroutines.js
@@ -133,7 +133,7 @@ function lsInner(gd) {
         } else {
             var xDomain = plotinfo.xaxis.domain;
             var yDomain = plotinfo.yaxis.domain;
-            var plotgroup = plotinfo.plotgroup;
+            var plotgroup = plotinfo.plotgroup[0];
 
             if(overlappingDomain(xDomain, yDomain, lowerDomains) && subplot.indexOf(zindexSeparator) === -1) {
                 var pgNode = plotgroup.node();
diff --git a/src/plots/cartesian/index.js b/src/plots/cartesian/index.js
index 07863ebbdf1..1820bc27a4e 100644
--- a/src/plots/cartesian/index.js
+++ b/src/plots/cartesian/index.js
@@ -159,7 +159,7 @@ exports.plot = function(gd, traces, transitionOpts, makeOnCompleteCallback) {
                 idWithZ += zindexSeparator + (z + 1);
                 subplotInfo = Lib.extendFlat({}, subplotInfo, {
                     id: idWithZ,
-                    plot: fullLayout._cartesianlayer.selectAll('.subplot').select('.' + idWithZ)
+                    plot: fullLayout._cartesianlayerAbove.selectAll('.subplot').select('.' + idWithZ)
                 });
             }
 
@@ -331,7 +331,11 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
     if(oldFullLayout._hasOnlyLargeSploms && !newFullLayout._hasOnlyLargeSploms) {
         for(k in oldPlots) {
             plotinfo = oldPlots[k];
-            if(plotinfo.plotgroup) plotinfo.plotgroup.remove();
+            if(plotinfo.plotgroup) {
+                for(var idx = plotinfo.plotgroup.length - 1; idx >= 0; idx--) {
+                    plotinfo.plotgroup[idx].remove();
+                }
+            }
         }
     }
 
@@ -362,8 +366,8 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
 
     if(hadCartesian && !hasCartesian) {
         // if we've gotten rid of all cartesian traces, remove all the subplot svg items
-
-        purgeSubplotLayers(oldFullLayout._cartesianlayer.selectAll('.subplot'), oldFullLayout);
+        purgeSubplotLayers(oldFullLayout._cartesianlayerBelow.selectAll('.subplot'), oldFullLayout);
+        purgeSubplotLayers(oldFullLayout._cartesianlayerAbove.selectAll('.subplot'), oldFullLayout);
         oldFullLayout._defs.selectAll('.axesclip').remove();
         delete oldFullLayout._axisConstraintGroups;
         delete oldFullLayout._axisMatchGroups;
@@ -378,7 +382,8 @@ exports.clean = function(newFullData, newFullLayout, oldFullData, oldFullLayout)
 
             if(!newPlots[oldSubplotId]) {
                 var selector = '.' + oldSubplotId + ',.' + oldSubplotId + '-x,.' + oldSubplotId + '-y';
-                oldFullLayout._cartesianlayer.selectAll(selector).remove();
+                oldFullLayout._cartesianlayerAbove.selectAll(selector).remove();
+                oldFullLayout._cartesianlayerBelow.selectAll(selector).remove();
                 removeSubplotExtras(oldSubplotId, oldFullLayout);
             }
         }
@@ -427,19 +432,36 @@ exports.drawFramework = function(gd) {
         subplotData = subplotData.concat(newSubplotData);
     }
 
-    var subplotLayers = fullLayout._cartesianlayer.selectAll('.subplot')
+    var subplotLayersAbove = fullLayout._cartesianlayerAbove.selectAll('.subplot')
         .data(subplotData, String);
 
-
-    subplotLayers.enter().append('g')
+    subplotLayersAbove.enter().append('g')
         .attr('class', function(d) { return 'subplot ' + d[0]; });
+    subplotLayersAbove.order();
+    subplotLayersAbove.exit()
+        .call(purgeSubplotLayers, fullLayout);
 
-    subplotLayers.order();
-
-    subplotLayers.exit()
+    var subplotLayersBelow = fullLayout._cartesianlayerBelow.selectAll('.subplot')
+        .data(initialSubplotData, String);
+    subplotLayersBelow.enter().append('g')
+        .attr('class', function(d) { return 'subplot ' + d[0] + '-below'; });
+    subplotLayersBelow.order();
+    subplotLayersBelow.exit()
         .call(purgeSubplotLayers, fullLayout);
 
-    subplotLayers.each(function(d) {
+    subplotLayersBelow.each(function(d) {
+        var id = d[0];
+        var plotinfo = fullLayout._plots[id];
+
+        plotinfo.plotgroup = [d3.select(this)];
+        makeSubplotLayerBelow(gd, plotinfo);
+
+        // make separate drag layers for each subplot,
+        // but append them to paper rather than the plot groups,
+        // so they end up on top of the rest
+        plotinfo.draglayer = ensureSingle(fullLayout._draggers, 'g', id);
+    });
+    subplotLayersAbove.each(function(d) {
         var id = d[0];
         var posZ = id.indexOf(zindexSeparator);
         var hasZ = posZ !== -1;
@@ -448,19 +470,21 @@ exports.drawFramework = function(gd) {
             id;
 
         var plotinfo = fullLayout._plots[id];
-        if(!plotinfo) {
+        if(plotinfo) {
+            plotinfo.plotgroup = plotinfo.plotgroup.concat([d3.select(this)]);
+        } else { // repurpose plotinfo from plot without z
             plotinfo = Lib.extendFlat({}, fullLayout._plots[idWithoutZ]);
 
             if(plotinfo) {
                 plotinfo.id = id;
                 fullLayout._plots[id] = plotinfo;
                 fullLayout._subplots.cartesian.push(id);
+                plotinfo.plotgroup[1] = d3.select(this);    
             }
         }
 
         if(plotinfo) {
-            plotinfo.plotgroup = d3.select(this);
-            makeSubplotLayer(gd, plotinfo);
+            makeSubplotLayerAbove(gd, plotinfo);
 
             if(!hasZ) {
                 // make separate drag layers for each subplot,
@@ -473,7 +497,7 @@ exports.drawFramework = function(gd) {
 };
 
 exports.rangePlot = function(gd, plotinfo, cdSubplot) {
-    makeSubplotLayer(gd, plotinfo);
+    makeSubplotLayerAbove(gd, plotinfo);
     plotOne(gd, plotinfo, cdSubplot);
     Plots.style(gd);
 };
@@ -556,9 +580,65 @@ function makeSubplotData(gd) {
     return subplotData;
 }
 
-function makeSubplotLayer(gd, plotinfo) {
+function makeSubplotLayerBelow(gd, plotinfo) {
     var fullLayout = gd._fullLayout;
-    var plotgroup = plotinfo.plotgroup;
+    var plotgroup = plotinfo.plotgroup[0];
+    var id = plotinfo.id;
+    var posZ = id.indexOf(zindexSeparator);
+    var hasZ = posZ !== -1;
+    var hasMultipleZ = fullLayout._zindices.length > 1;
+    var hasOnlyLargeSploms = fullLayout._hasOnlyLargeSploms;
+    var mainplotinfo = plotinfo.mainplotinfo;
+
+    if(!plotinfo.mainplot || hasMultipleZ) {
+        if (!hasOnlyLargeSploms && !hasZ) {
+            var backLayer = ensureSingle(plotgroup, 'g', 'layer-subplot');
+            plotinfo.shapelayer = ensureSingle(backLayer, 'g', 'shapelayer');
+            plotinfo.imagelayer = ensureSingle(backLayer, 'g', 'imagelayer');
+    
+            if(mainplotinfo && hasMultipleZ) {
+                plotinfo.minorGridlayer = mainplotinfo.minorGridlayer;
+                plotinfo.gridlayer = mainplotinfo.gridlayer;
+                plotinfo.zerolinelayer = mainplotinfo.zerolinelayer;
+            } else {
+                plotinfo.minorGridlayer = ensureSingle(plotgroup, 'g', 'minor-gridlayer');
+                plotinfo.gridlayer = ensureSingle(plotgroup, 'g', 'gridlayer');
+                plotinfo.zerolinelayer = ensureSingle(plotgroup, 'g', 'zerolinelayer');
+            }
+        }
+    } else {
+        // now make the components of overlaid subplots
+        // overlays don't have backgrounds, and append all
+        // their other components to the corresponding
+        // extra groups of their main plots.
+
+        plotinfo.minorGridlayer = mainplotinfo.minorGridlayer;
+        plotinfo.gridlayer = mainplotinfo.gridlayer;
+        plotinfo.zerolinelayer = mainplotinfo.zerolinelayer;
+    }
+
+    // common attributes for all subplots, overlays or not
+    if(!hasZ) {
+        if(!hasOnlyLargeSploms) {
+            ensureSingleAndAddDatum(plotinfo.minorGridlayer, 'g', plotinfo.xaxis._id);
+            ensureSingleAndAddDatum(plotinfo.minorGridlayer, 'g', plotinfo.yaxis._id);
+            plotinfo.minorGridlayer.selectAll('g')
+                .map(function(d) { return d[0]; })
+                .sort(axisIds.idSort);
+    
+            ensureSingleAndAddDatum(plotinfo.gridlayer, 'g', plotinfo.xaxis._id);
+            ensureSingleAndAddDatum(plotinfo.gridlayer, 'g', plotinfo.yaxis._id);
+            plotinfo.gridlayer.selectAll('g')
+                .map(function(d) { return d[0]; })
+                .sort(axisIds.idSort);
+        }
+    }
+}
+
+function makeSubplotLayerAbove(gd, plotinfo) {
+	var fullLayout = gd._fullLayout;
+	var plotgroup = plotinfo.plotgroup;
+    var plotgroup = plotinfo.plotgroup[1];
     var id = plotinfo.id;
 
     var posZ = id.indexOf(zindexSeparator);
@@ -584,24 +664,6 @@ function makeSubplotLayer(gd, plotinfo) {
             plotinfo.yaxislayer = ensureSingle(plotgroup, 'g', 'yaxislayer-above');
         } else {
             if(!hasZ) {
-                var backLayer = ensureSingle(plotgroup, 'g', 'layer-subplot');
-                plotinfo.shapelayer = ensureSingle(backLayer, 'g', 'shapelayer');
-                plotinfo.imagelayer = ensureSingle(backLayer, 'g', 'imagelayer');
-
-                if(mainplotinfo && hasMultipleZ) {
-                    plotinfo.minorGridlayer = mainplotinfo.minorGridlayer;
-                    plotinfo.gridlayer = mainplotinfo.gridlayer;
-                    plotinfo.zerolinelayer = mainplotinfo.zerolinelayer;
-                } else {
-                    plotinfo.minorGridlayer = ensureSingle(plotgroup, 'g', 'minor-gridlayer');
-                    plotinfo.gridlayer = ensureSingle(plotgroup, 'g', 'gridlayer');
-                    plotinfo.zerolinelayer = ensureSingle(plotgroup, 'g', 'zerolinelayer');
-                }
-
-                var betweenLayer = ensureSingle(plotgroup, 'g', 'layer-between');
-                plotinfo.shapelayerBetween = ensureSingle(betweenLayer, 'g', 'shapelayer');
-                plotinfo.imagelayerBetween = ensureSingle(betweenLayer, 'g', 'imagelayer');
-
                 ensureSingle(plotgroup, 'path', 'xlines-below');
                 ensureSingle(plotgroup, 'path', 'ylines-below');
                 plotinfo.overlinesBelow = ensureSingle(plotgroup, 'g', 'overlines-below');
@@ -631,7 +693,8 @@ function makeSubplotLayer(gd, plotinfo) {
             }
         }
     } else {
-        var mainplotgroup = mainplotinfo.plotgroup;
+        var mainplotinfo = plotinfo.mainplotinfo;
+        var mainplotgroup = mainplotinfo.plotgroup[1];
         var xId = id + '-x';
         var yId = id + '-y';
 
@@ -640,10 +703,6 @@ function makeSubplotLayer(gd, plotinfo) {
         // their other components to the corresponding
         // extra groups of their main plots.
 
-        plotinfo.minorGridlayer = mainplotinfo.minorGridlayer;
-        plotinfo.gridlayer = mainplotinfo.gridlayer;
-        plotinfo.zerolinelayer = mainplotinfo.zerolinelayer;
-
         ensureSingle(mainplotinfo.overlinesBelow, 'path', xId);
         ensureSingle(mainplotinfo.overlinesBelow, 'path', yId);
         ensureSingle(mainplotinfo.overaxesBelow, 'g', xId);
@@ -666,20 +725,6 @@ function makeSubplotLayer(gd, plotinfo) {
     if(!hasZ) {
         // common attributes for all subplots, overlays or not
 
-        if(!hasOnlyLargeSploms) {
-            ensureSingleAndAddDatum(plotinfo.minorGridlayer, 'g', plotinfo.xaxis._id);
-            ensureSingleAndAddDatum(plotinfo.minorGridlayer, 'g', plotinfo.yaxis._id);
-            plotinfo.minorGridlayer.selectAll('g')
-                .map(function(d) { return d[0]; })
-                .sort(axisIds.idSort);
-
-            ensureSingleAndAddDatum(plotinfo.gridlayer, 'g', plotinfo.xaxis._id);
-            ensureSingleAndAddDatum(plotinfo.gridlayer, 'g', plotinfo.yaxis._id);
-            plotinfo.gridlayer.selectAll('g')
-                .map(function(d) { return d[0]; })
-                .sort(axisIds.idSort);
-        }
-
         plotinfo.xlines
             .style('fill', 'none')
             .classed('crisp', true);
diff --git a/test/image/baselines/zz_shapes_layer_between_xref_paper.png b/test/image/baselines/zz_shapes_layer_between_xref_paper.png
new file mode 100644
index 00000000000..480e71cc96a
Binary files /dev/null and b/test/image/baselines/zz_shapes_layer_between_xref_paper.png differ
diff --git a/test/image/mocks/zz_shapes_layer_between_xref_paper.json b/test/image/mocks/zz_shapes_layer_between_xref_paper.json
new file mode 100644
index 00000000000..b538ecdb432
--- /dev/null
+++ b/test/image/mocks/zz_shapes_layer_between_xref_paper.json
@@ -0,0 +1,36 @@
+{
+    "data": [
+        {
+            "x": [
+                1, 2, 3, 4, 5, 6, 7
+            ],
+            "y": [
+                -1000, 0, 1000, 2000, 3000, 4000, 5000
+            ]
+        }
+    ],
+    "layout": {
+        "shapes": [
+
+            {
+                "layer": "between",
+                "name": "my zeroline y2",
+                "line": {
+                  "color": "yellow",
+                  "width": 3.0
+                },
+                "x0": 0,
+                "x1": 1,
+                "xref": "paper",
+                "y0": 0,
+                "y1": 0,
+                "yref": "y"
+              }
+        ],
+        "yaxis": {
+            "ticklabelposition": "inside top",
+            "zeroline": false
+        }
+        
+    }
+}
diff --git a/test/jasmine/tests/cartesian_test.js b/test/jasmine/tests/cartesian_test.js
index 617726c202c..b5942ef26b0 100644
--- a/test/jasmine/tests/cartesian_test.js
+++ b/test/jasmine/tests/cartesian_test.js
@@ -436,7 +436,7 @@ describe('subplot creation / deletion:', function() {
 
     function checkBGLayers(behindCount, x2y2Count, subplots) {
         expect(gd.querySelectorAll('.bglayer rect.bg').length).toBe(behindCount);
-        expect(gd.querySelectorAll('.subplot.x2y2 rect.bg').length).toBe(x2y2Count);
+        expect(gd.querySelectorAll('.subplot.x2y2-below rect.bg').length).toBe(x2y2Count);
 
         // xy is the first subplot, so it never gets put in front of others
         expect(gd.querySelectorAll('.subplot.xy rect.bg').length).toBe(0);
@@ -445,7 +445,7 @@ describe('subplot creation / deletion:', function() {
         expect(gd.querySelectorAll('.subplot.xy3 rect.bg').length).toBe(0);
 
         // verify that these are *all* the subplots and backgrounds we have
-        expect(gd.querySelectorAll('.subplot').length).toBe(subplots.length);
+        expect(gd.querySelectorAll('.subplot').length).toBe(subplots.length * 2);
         subplots.forEach(function(subplot) {
             expect(gd.querySelectorAll('.subplot.' + subplot).length).toBe(1);
         });
@@ -791,14 +791,15 @@ describe('subplot creation / deletion:', function() {
     it('clear axis ticks, labels and title when relayout an axis to `*visible:false*', function(done) {
         function _assert(xaxis, yaxis) {
             var g = d3Select('.subplot.xy');
+            var gBelow = d3Select('.subplot.xy-below');
             var info = d3Select('.infolayer');
 
             expect(g.selectAll('.xtick').size()).toBe(xaxis[0], 'x tick cnt');
-            expect(g.selectAll('.gridlayer .xgrid').size()).toBe(xaxis[1], 'x gridline cnt');
+            expect(gBelow.selectAll('.gridlayer .xgrid').size()).toBe(xaxis[1], 'x gridline cnt');
             expect(info.selectAll('.g-xtitle').size()).toBe(xaxis[2], 'x title cnt');
 
             expect(g.selectAll('.ytick').size()).toBe(yaxis[0], 'y tick cnt');
-            expect(g.selectAll('.gridlayer .ygrid').size()).toBe(yaxis[1], 'y gridline cnt');
+            expect(gBelow.selectAll('.gridlayer .ygrid').size()).toBe(yaxis[1], 'y gridline cnt');
             expect(info.selectAll('.g-ytitle').size()).toBe(yaxis[2], 'y title cnt');
         }
 
diff --git a/test/jasmine/tests/plot_interact_test.js b/test/jasmine/tests/plot_interact_test.js
index e091148b807..5ed4754495c 100644
--- a/test/jasmine/tests/plot_interact_test.js
+++ b/test/jasmine/tests/plot_interact_test.js
@@ -25,10 +25,12 @@ describe('Test plot structure', function() {
     afterEach(destroyGraphDiv);
 
     describe('cartesian plots', function() {
-        function countSubplots() {
-            return d3SelectAll('g.subplot').size();
+        function countSubplotsBackground() {
+            return d3SelectAll('g.cartesianlayer-below g.subplot').size();
+        }
+        function countSubplotsForeground() {
+            return d3SelectAll('g.cartesianlayer g.subplot').size();
         }
-
         function countScatterTraces() {
             return d3SelectAll('g.trace.scatter').size();
         }
@@ -58,8 +60,9 @@ describe('Test plot structure', function() {
                 Plotly.newPlot(gd, mockData, mockLayout).then(done);
             });
 
-            it('has one *subplot xy* node', function() {
-                expect(countSubplots()).toEqual(1);
+            it('has one *subplot xy* node each in background and foreground', function() {
+                expect(countSubplotsBackground()).toEqual(1);
+                expect(countSubplotsForeground()).toEqual(1);
             });
 
             it('has four clip paths', function() {
@@ -101,19 +104,22 @@ describe('Test plot structure', function() {
 
             it('should be able to get deleted', function(done) {
                 expect(countScatterTraces()).toEqual(mock.data.length);
-                expect(countSubplots()).toEqual(1);
+                expect(countSubplotsBackground()).toEqual(1);
+                expect(countSubplotsForeground()).toEqual(1);
 
                 Plotly.deleteTraces(gd, [0]).then(function() {
                     expect(countScatterTraces()).toEqual(0);
-                    expect(countSubplots()).toEqual(1);
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
                     expect(countClipPaths()).toEqual(4);
                     expect(countDraggers()).toEqual(1);
 
                     return Plotly.relayout(gd, {xaxis: null, yaxis: null});
                 }).then(function() {
                     expect(countScatterTraces()).toEqual(0);
-                    // we still make one empty cartesian subplot if no other subplots are described
-                    expect(countSubplots()).toEqual(1);
+                    // we still make two empty cartesian subplots (bg and fg) if no other subplots are described
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
                     expect(countClipPaths()).toEqual(4);
                     expect(countDraggers()).toEqual(1);
                 })
@@ -122,40 +128,46 @@ describe('Test plot structure', function() {
 
             it('should restore layout axes when they get deleted', function(done) {
                 expect(countScatterTraces()).toEqual(mock.data.length);
-                expect(countSubplots()).toEqual(1);
+                expect(countSubplotsBackground()).toEqual(1);
+                expect(countSubplotsForeground()).toEqual(1);
 
                 Plotly.relayout(gd, {xaxis: null, yaxis: null})
                 .then(function() {
                     expect(countScatterTraces()).toEqual(1);
-                    expect(countSubplots()).toEqual(1);
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
                     expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4);
                     expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4);
 
                     return Plotly.relayout(gd, 'xaxis', null);
                 }).then(function() {
                     expect(countScatterTraces()).toEqual(1);
-                    expect(countSubplots()).toEqual(1);
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
                     expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4);
                     expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4);
 
                     return Plotly.relayout(gd, 'xaxis', {});
                 }).then(function() {
                     expect(countScatterTraces()).toEqual(1);
-                    expect(countSubplots()).toEqual(1);
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
                     expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4);
                     expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4);
 
                     return Plotly.relayout(gd, 'yaxis', null);
                 }).then(function() {
                     expect(countScatterTraces()).toEqual(1);
-                    expect(countSubplots()).toEqual(1);
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
                     expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4);
                     expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4);
 
                     return Plotly.relayout(gd, 'yaxis', {});
                 }).then(function() {
                     expect(countScatterTraces()).toEqual(1);
-                    expect(countSubplots()).toEqual(1);
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
                     expect(gd.layout.xaxis.range).toBeCloseToArray([-4.79980, 74.48580], 4);
                     expect(gd.layout.yaxis.range).toBeCloseToArray([-1.2662, 17.67023], 4);
                 })
@@ -203,7 +215,8 @@ describe('Test plot structure', function() {
                 });
 
                 it('has four *subplot* nodes', function() {
-                    expect(countSubplots()).toEqual(4);
+                    expect(countSubplotsBackground()).toEqual(4);
+                    expect(countSubplotsForeground()).toEqual(4);
                     expect(countClipPaths()).toEqual(12);
                     expect(countDraggers()).toEqual(4);
                 });
@@ -245,8 +258,9 @@ describe('Test plot structure', function() {
                     .then(done);
                 });
 
-                it('has four *subplot* nodes', function() {
-                    expect(countSubplots()).toEqual(4);
+                it('has 4 *subplot* nodes', function() {
+                    expect(countSubplotsBackground()).toEqual(4);
+                    expect(countSubplotsForeground()).toEqual(4);
                     expect(countClipPaths()).toEqual(12);
                     expect(countDraggers()).toEqual(4);
                 });
@@ -285,7 +299,8 @@ describe('Test plot structure', function() {
                 }
 
                 it('should be removed of traces in sequence', function(done) {
-                    expect(countSubplots()).toEqual(4);
+                    expect(countSubplotsBackground()).toEqual(4);
+                    expect(countSubplotsForeground()).toEqual(4);
                     assertHeatmapNodes(4);
                     assertContourNodes(2);
                     expect(countColorBars()).toEqual(1);
@@ -298,7 +313,8 @@ describe('Test plot structure', function() {
                     });
 
                     Plotly.deleteTraces(gd, [0]).then(function() {
-                        expect(countSubplots()).toEqual(3);
+                        expect(countSubplotsBackground()).toEqual(3);
+                        expect(countSubplotsForeground()).toEqual(3);
                         expect(countClipPaths()).toEqual(11);
                         expect(countDraggers()).toEqual(3);
                         assertHeatmapNodes(3);
@@ -314,7 +330,8 @@ describe('Test plot structure', function() {
 
                         return Plotly.deleteTraces(gd, [0]);
                     }).then(function() {
-                        expect(countSubplots()).toEqual(2);
+                        expect(countSubplotsBackground()).toEqual(2);
+                        expect(countSubplotsForeground()).toEqual(2);
                         expect(countClipPaths()).toEqual(7);
                         expect(countDraggers()).toEqual(2);
                         assertHeatmapNodes(2);
@@ -330,7 +347,8 @@ describe('Test plot structure', function() {
 
                         return Plotly.deleteTraces(gd, [0]);
                     }).then(function() {
-                        expect(countSubplots()).toEqual(1);
+                        expect(countSubplotsBackground()).toEqual(1);
+                        expect(countSubplotsForeground()).toEqual(1);
                         expect(countClipPaths()).toEqual(4);
                         expect(countDraggers()).toEqual(1);
                         assertHeatmapNodes(1);
@@ -346,7 +364,8 @@ describe('Test plot structure', function() {
 
                         return Plotly.deleteTraces(gd, [0]);
                     }).then(function() {
-                        expect(countSubplots()).toEqual(1);
+                        expect(countSubplotsBackground()).toEqual(1);
+                        expect(countSubplotsForeground()).toEqual(1);
                         expect(countClipPaths()).toEqual(4);
                         expect(countDraggers()).toEqual(1);
                         assertHeatmapNodes(0);
@@ -369,7 +388,8 @@ describe('Test plot structure', function() {
 
                         return Plotly.relayout(gd, update);
                     }).then(function() {
-                        expect(countSubplots()).toEqual(1);
+                        expect(countSubplotsBackground()).toEqual(1);
+                        expect(countSubplotsForeground()).toEqual(1);
                         expect(countClipPaths()).toEqual(4);
                         expect(countDraggers()).toEqual(1);
                         assertHeatmapNodes(0);
@@ -434,11 +454,13 @@ describe('Test plot structure', function() {
 
             it('should be able to get deleted', function(done) {
                 expect(countPieTraces()).toEqual(1);
-                expect(countSubplots()).toEqual(0);
+                expect(countSubplotsBackground()).toEqual(0);
+                expect(countSubplotsForeground()).toEqual(0);
 
                 Plotly.deleteTraces(gd, [0]).then(function() {
                     expect(countPieTraces()).toEqual(0);
-                    expect(countSubplots()).toEqual(1);
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
                 })
                 .then(done, done.fail);
             });
@@ -446,18 +468,21 @@ describe('Test plot structure', function() {
             it('should be able to be restyled to a bar chart and back', function(done) {
                 expect(countPieTraces()).toEqual(1);
                 expect(countBarTraces()).toEqual(0);
-                expect(countSubplots()).toEqual(0);
+                expect(countSubplotsBackground()).toEqual(0);
+                expect(countSubplotsForeground()).toEqual(0);
 
                 Plotly.restyle(gd, 'type', 'bar').then(function() {
                     expect(countPieTraces()).toEqual(0);
                     expect(countBarTraces()).toEqual(1);
-                    expect(countSubplots()).toEqual(1);
+                    expect(countSubplotsBackground()).toEqual(1);
+                    expect(countSubplotsForeground()).toEqual(1);
 
                     return Plotly.restyle(gd, 'type', 'pie');
                 }).then(function() {
                     expect(countPieTraces()).toEqual(1);
                     expect(countBarTraces()).toEqual(0);
-                    expect(countSubplots()).toEqual(0);
+                    expect(countSubplotsBackground()).toEqual(0);
+                    expect(countSubplotsForeground()).toEqual(0);
                 })
                 .then(done, done.fail);
             });
diff --git a/test/jasmine/tests/splom_test.js b/test/jasmine/tests/splom_test.js
index 44cede6e3fe..1bdc9c9646b 100644
--- a/test/jasmine/tests/splom_test.js
+++ b/test/jasmine/tests/splom_test.js
@@ -740,17 +740,27 @@ describe('Test splom interactions:', function() {
             var msg = ' - call #' + cnt;
             var gd3 = d3Select(gd);
             var subplots = gd3.selectAll('g.cartesianlayer > g.subplot');
+            var subplotsBelow = gd3.selectAll('g.cartesianlayer-below > g.subplot');
             var bgs = gd3.selectAll('.bglayer > rect.bg');
 
             expect(subplots.size())
-                .toBe(exp.subplotCnt, '# of <g.subplot>' + msg);
+            .toBe(exp.subplotCnt, '# of <g.subplot>' + msg);
 
             var failedSubplots = [];
             subplots.each(function(d, i) {
                 var actual = this.children.length;
                 var expected = typeof exp.innerSubplotNodeCnt === 'function' ?
-                    exp.innerSubplotNodeCnt(d[0], i) :
-                    exp.innerSubplotNodeCnt;
+                exp.innerSubplotNodeCnt(d[0], i) :
+                exp.innerSubplotNodeCnt;
+                if(actual !== expected) {
+                    failedSubplots.push([d, actual, 'vs', expected].join(' '));
+                }
+            });
+            subplotsBelow.each(function(d, i) {
+                var actual = this.children.length;
+                var expected = typeof exp.innerSubplotNodeCntBelow === 'function' ?
+                exp.innerSubplotNodeCntBelow(d[0], i) :
+                exp.innerSubplotNodeCntBelow;
                 if(actual !== expected) {
                     failedSubplots.push([d, actual, 'vs', expected].join(' '));
                 }
@@ -769,6 +779,7 @@ describe('Test splom interactions:', function() {
         _newPlot(gd, figLarge).then(function() {
             _assert({
                 subplotCnt: 400,
+                innerSubplotNodeCntBelow: 0,
                 innerSubplotNodeCnt: 4,
                 hasSplomGrid: true,
                 bgCnt: 0
@@ -779,6 +790,7 @@ describe('Test splom interactions:', function() {
         .then(function() {
             _assert({
                 subplotCnt: 400,
+                innerSubplotNodeCntBelow: 0,
                 innerSubplotNodeCnt: 4,
                 hasSplomGrid: true,
                 bgCnt: 400
@@ -789,6 +801,7 @@ describe('Test splom interactions:', function() {
         .then(function() {
             _assert({
                 subplotCnt: 400,
+                innerSubplotNodeCntBelow: 0,
                 innerSubplotNodeCnt: 4,
                 hasSplomGrid: true,
                 bgCnt: 0
@@ -799,28 +812,12 @@ describe('Test splom interactions:', function() {
         .then(function() {
             _assert({
                 subplotCnt: 25,
-                innerSubplotNodeCnt: 18,
+                innerSubplotNodeCntBelow: 4,
+                innerSubplotNodeCnt: 13,
                 hasSplomGrid: false,
                 bgCnt: 0
             });
 
-            // make sure 'new' subplot layers are in order
-            var gridIndex = -1;
-            var xaxisIndex = -1;
-            var subplot0 = d3Select('g.cartesianlayer > g.subplot').node();
-            for(var i in subplot0.children) {
-                var cl = subplot0.children[i].classList;
-                if(cl) {
-                    if(cl.contains('gridlayer')) gridIndex = +i;
-                    else if(cl.contains('xaxislayer-above')) xaxisIndex = +i;
-                }
-            }
-            // from large -> small splom:
-            // grid layer would be above xaxis layer,
-            // if we didn't clear subplot children.
-            expect(gridIndex).toBe(2, '<g.gridlayer> index');
-            expect(xaxisIndex).toBe(15, '<g.xaxislayer-above> index');
-
             return Plotly.restyle(gd, 'dimensions', [dimsLarge]);
         })
         .then(function() {
@@ -829,9 +826,13 @@ describe('Test splom interactions:', function() {
                 // from small -> large splom:
                 // no need to clear subplots children in existing subplots,
                 // new subplots though have reduced number of children.
+                innerSubplotNodeCntBelow: function(d) {
+                    var p = d.match(SUBPLOT_PATTERN);
+                    return (p[1] > 5 || p[2] > 5) ? 0 : 4;
+                },
                 innerSubplotNodeCnt: function(d) {
                     var p = d.match(SUBPLOT_PATTERN);
-                    return (p[1] > 5 || p[2] > 5) ? 4 : 18;
+                    return (p[1] > 5 || p[2] > 5) ? 4 : 13;
                 },
                 hasSplomGrid: true,
                 bgCnt: 0