diff --git a/docs/index.md b/docs/index.md
index e2dc828fc..da159bb5f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -336,6 +336,7 @@ The Cypress API enables you to configure the behavior of how Cypress works inter
- [root element attributes](./recipes/root-attributes.md)
- [Parse Email URL](./recipes/parse-email-url.md)
- [Find All Buttons Without `data-cy` attribute](./recipes/find-buttons-without-data-cy.md)
+- Detect [layout shift](./recipes/layout-shift.md)
### Working with the window object
diff --git a/docs/recipes/layout-shift.md b/docs/recipes/layout-shift.md
new file mode 100644
index 000000000..90124951d
--- /dev/null
+++ b/docs/recipes/layout-shift.md
@@ -0,0 +1,53 @@
+# Layout Shift
+
+📺 Watch this recipe explained in the video [Test Layout Shift](https://youtu.be/5OTqNxJyhxo).
+
+
+
+```html hide
+
+
🩶
+
Some text after...
+```
+
+Change the CSS below to give the liked element some small padding. This will make the test fail, since we will detect the vertical shift.
+
+```css hide
+.liked {
+ padding-top: 0px;
+}
+```
+
+```js app hide
+let liked = false
+const heart = document.getElementById('status')
+document.getElementById('like').addEventListener('click', () => {
+ if (!liked) {
+ liked = true
+ heart.innerText = '❤️'
+ heart.classList.add('liked')
+ } else {
+ liked = false
+ heart.innerText = '🩶'
+ heart.classList.remove('liked')
+ }
+})
+```
+
+Let's use [offsetTop](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetTop) property to remember the element's position at the start of the interaction.
+
+```js hide
+cy.get('#other')
+ .should('have.prop', 'offsetTop')
+ .should('be.a', 'number')
+ .then((offsetTop) => {
+ // interact with the app
+ cy.contains('button', 'Like').click()
+ // check if the element remains at the same position vertically
+ cy.get('#other').should('have.prop', 'offsetTop', offsetTop)
+ })
+```
+
+We can detect the horizontal shift similarly using the `offsetLeft` property.
+
+
diff --git a/package-lock.json b/package-lock.json
index 5135d3ce6..1f7b01b8d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14041,7 +14041,6 @@
},
"node_modules/npm/node_modules/lodash._baseindexof": {
"version": "3.1.0",
- "dev": true,
"inBundle": true,
"license": "MIT"
},
@@ -14057,19 +14056,16 @@
},
"node_modules/npm/node_modules/lodash._bindcallback": {
"version": "3.0.1",
- "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/lodash._cacheindexof": {
"version": "3.0.2",
- "dev": true,
"inBundle": true,
"license": "MIT"
},
"node_modules/npm/node_modules/lodash._createcache": {
"version": "3.1.2",
- "dev": true,
"inBundle": true,
"license": "MIT",
"dependencies": {
@@ -14084,7 +14080,6 @@
},
"node_modules/npm/node_modules/lodash._getnative": {
"version": "3.9.1",
- "dev": true,
"inBundle": true,
"license": "MIT"
},
@@ -14102,7 +14097,6 @@
},
"node_modules/npm/node_modules/lodash.restparam": {
"version": "3.6.1",
- "dev": true,
"inBundle": true,
"license": "MIT"
},
@@ -31368,8 +31362,7 @@
},
"lodash._baseindexof": {
"version": "3.1.0",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"lodash._baseuniq": {
"version": "4.6.0",
@@ -31382,18 +31375,15 @@
},
"lodash._bindcallback": {
"version": "3.0.1",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"lodash._cacheindexof": {
"version": "3.0.2",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"lodash._createcache": {
"version": "3.1.2",
"bundled": true,
- "dev": true,
"requires": {
"lodash._getnative": "^3.0.0"
}
@@ -31405,8 +31395,7 @@
},
"lodash._getnative": {
"version": "3.9.1",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"lodash._root": {
"version": "3.0.1",
@@ -31420,8 +31409,7 @@
},
"lodash.restparam": {
"version": "3.6.1",
- "bundled": true,
- "dev": true
+ "bundled": true
},
"lodash.union": {
"version": "4.6.0",