Repository: tailwindlabs/tailwindcss

Problem statement:
[Feature request] Add overscroll options
On mobile UIs, you can have something called [`overscroll-behaviour`](https://developer.mozilla.org/en-US/docs/Web/CSS/overscroll-behavior) which can help on removing 'pull to refresh' when scrolling.

It is also useful for chat boxes or other contained UI elements - see [this MDN example](https://mdn.github.io/css-examples/overscroll-behavior/).

It would be really handy to add this to Tailwind!

### Values
- `auto` - The default scroll overflow behavior occurs as normal.
- `contain` - Default scroll overflow behavior is observed inside the element this value is set on (e.g. "bounce" effects or refreshes), but no scroll chaining occurs to neighbouring scrolling areas, e.g. underlying elements will not scroll.
- `none` - No scroll chaining occurs to neighbouring scrolling areas, and default scroll overflow behavior is prevented.

There is `overscroll-behaviour`, `overscroll-behaviour-y` and `overscroll-behaviour-x`.

### Proposed API

Add the following class definitions:

```css
.overscroll-auto {
  overscroll-behaviour: auto;
}
.overscroll-contain {
  overscroll-behaviour: contain;
}
.overscroll-none {
  overscroll-behaviour: none;
}

.overscroll-y-auto {
  overscroll-behaviour-y: auto;
}
.overscroll-y-contain {
  overscroll-behaviour-y: contain;
}
.overscroll-y-none {
  overscroll-behaviour-y: none;
}

.overscroll-x-auto {
  overscroll-behaviour-x: auto;
}
.overscroll-x-contain {
  overscroll-behaviour-x: contain;
}
.overscroll-x-none {
  overscroll-behaviour-x: none;
}
```


Hints:
This can easily be added as a plugin in the short term:

```js
const plugin = require('tailwindcss/plugin');

module.exports = {
    plugins: [
        plugin(function ({ addUtilities }) {
            const newUtilities = {
                '.overscroll-auto': {
                    'overscroll-behavior': 'auto',
                },
                '.overscroll-contain': {
                    'overscroll-behavior': 'contain',
                },
                '.overscroll-none': {
                    'overscroll-behavior': 'none',
                },
                '.overscroll-y-auto': {
                    'overscroll-behavior-y': 'auto',
                },
                '.overscroll-y-contain': {
                    'overscroll-behavior-y': 'contain',
                },
                '.overscroll-y-none': {
                    'overscroll-behavior-y': 'none',
                },
                '.overscroll-x-auto': {
                    'overscroll-behavior-x': 'auto',
                },
                '.overscroll-x-contain': {
                    'overscroll-behavior-x': 'contain',
                },
                '.overscroll-x-none': {
                    'overscroll-behavior-x': 'none',
                },
            };
            addUtilities(newUtilities);
        }),
    ],
};

```
@leevigraham That's fantastic! I wasn't sure how to structure the plugin personally.
Thanks @leevigraham. Fyi, for anyone trying to get this to work, the CSS property is `behavior` rather than `behaviour`.
> Thanks @leevigraham. Fyi, for anyone trying to get this to work, the CSS property is behavior rather than behaviour.

Woops… updated my comment :)
Would this be accepted as a PR? Seems within the scope and style of Tailwind.
@wadefletch Go ahead and make one!

Patch:
diff --git a/src/corePlugins.js b/src/corePlugins.js
--- a/src/corePlugins.js
+++ b/src/corePlugins.js
@@ -46,6 +46,7 @@ import objectPosition from './plugins/objectPosition'
 import opacity from './plugins/opacity'
 import outline from './plugins/outline'
 import overflow from './plugins/overflow'
+import overscroll from './plugins/overscroll'
 import padding from './plugins/padding'
 import placeholderColor from './plugins/placeholderColor'
 import pointerEvents from './plugins/pointerEvents'
@@ -154,6 +155,7 @@ export default function({ corePlugins: corePluginConfig }) {
     opacity,
     outline,
     overflow,
+    overscroll,
     padding,
     placeholderColor,
     placeholderOpacity,
diff --git a/src/plugins/overscroll.js b/src/plugins/overscroll.js
new file mode 100644
--- /dev/null
+++ b/src/plugins/overscroll.js
@@ -0,0 +1,18 @@
+export default function() {
+  return function({ addUtilities, variants }) {
+    addUtilities(
+      {
+        '.overscroll-auto': { 'overscroll-behavior': 'auto' },
+        '.overscroll-contain': { 'overscroll-behavior': 'contain' },
+        '.overscroll-none': { 'overscroll-behavior': 'none' },
+        '.overscroll-y-auto': { 'overscroll-behavior-y': 'auto' },
+        '.overscroll-y-contain': { 'overscroll-behavior-y': 'contain' },
+        '.overscroll-y-none': { 'overscroll-behavior-y': 'none' },
+        '.overscroll-x-auto': { 'overscroll-behavior-x': 'auto' },
+        '.overscroll-x-contain': { 'overscroll-behavior-x': 'contain' },
+        '.overscroll-x-none': { 'overscroll-behavior-x': 'none' },
+      },
+      variants('overscroll')
+    )
+  }
+}


Test patch:
diff --git a/__tests__/fixtures/tailwind-output-ie11.css b/__tests__/fixtures/tailwind-output-ie11.css
--- a/__tests__/fixtures/tailwind-output-ie11.css
+++ b/__tests__/fixtures/tailwind-output-ie11.css
@@ -6089,6 +6089,42 @@ video {
   -webkit-overflow-scrolling: auto;
 }
 
+.overscroll-auto {
+  overscroll-behavior: auto;
+}
+
+.overscroll-contain {
+  overscroll-behavior: contain;
+}
+
+.overscroll-none {
+  overscroll-behavior: none;
+}
+
+.overscroll-y-auto {
+  overscroll-behavior-y: auto;
+}
+
+.overscroll-y-contain {
+  overscroll-behavior-y: contain;
+}
+
+.overscroll-y-none {
+  overscroll-behavior-y: none;
+}
+
+.overscroll-x-auto {
+  overscroll-behavior-x: auto;
+}
+
+.overscroll-x-contain {
+  overscroll-behavior-x: contain;
+}
+
+.overscroll-x-none {
+  overscroll-behavior-x: none;
+}
+
 .p-0 {
   padding: 0;
 }
diff --git a/__tests__/fixtures/tailwind-output-important.css b/__tests__/fixtures/tailwind-output-important.css
--- a/__tests__/fixtures/tailwind-output-important.css
+++ b/__tests__/fixtures/tailwind-output-important.css
@@ -7769,6 +7769,42 @@ video {
   -webkit-overflow-scrolling: auto !important;
 }
 
+.overscroll-auto {
+  overscroll-behavior: auto !important;
+}
+
+.overscroll-contain {
+  overscroll-behavior: contain !important;
+}
+
+.overscroll-none {
+  overscroll-behavior: none !important;
+}
+
+.overscroll-y-auto {
+  overscroll-behavior-y: auto !important;
+}
+
+.overscroll-y-contain {
+  overscroll-behavior-y: contain !important;
+}
+
+.overscroll-y-none {
+  overscroll-behavior-y: none !important;
+}
+
+.overscroll-x-auto {
+  overscroll-behavior-x: auto !important;
+}
+
+.overscroll-x-contain {
+  overscroll-behavior-x: contain !important;
+}
+
+.overscroll-x-none {
+  overscroll-behavior-x: none !important;
+}
+
 .p-0 {
   padding: 0 !important;
 }
diff --git a/__tests__/fixtures/tailwind-output-no-color-opacity.css b/__tests__/fixtures/tailwind-output-no-color-opacity.css
--- a/__tests__/fixtures/tailwind-output-no-color-opacity.css
+++ b/__tests__/fixtures/tailwind-output-no-color-opacity.css
@@ -6341,6 +6341,42 @@ video {
   -webkit-overflow-scrolling: auto;
 }
 
+.overscroll-auto {
+  overscroll-behavior: auto;
+}
+
+.overscroll-contain {
+  overscroll-behavior: contain;
+}
+
+.overscroll-none {
+  overscroll-behavior: none;
+}
+
+.overscroll-y-auto {
+  overscroll-behavior-y: auto;
+}
+
+.overscroll-y-contain {
+  overscroll-behavior-y: contain;
+}
+
+.overscroll-y-none {
+  overscroll-behavior-y: none;
+}
+
+.overscroll-x-auto {
+  overscroll-behavior-x: auto;
+}
+
+.overscroll-x-contain {
+  overscroll-behavior-x: contain;
+}
+
+.overscroll-x-none {
+  overscroll-behavior-x: none;
+}
+
 .p-0 {
   padding: 0;
 }
diff --git a/__tests__/fixtures/tailwind-output.css b/__tests__/fixtures/tailwind-output.css
--- a/__tests__/fixtures/tailwind-output.css
+++ b/__tests__/fixtures/tailwind-output.css
@@ -7769,6 +7769,42 @@ video {
   -webkit-overflow-scrolling: auto;
 }
 
+.overscroll-auto {
+  overscroll-behavior: auto;
+}
+
+.overscroll-contain {
+  overscroll-behavior: contain;
+}
+
+.overscroll-none {
+  overscroll-behavior: none;
+}
+
+.overscroll-y-auto {
+  overscroll-behavior-y: auto;
+}
+
+.overscroll-y-contain {
+  overscroll-behavior-y: contain;
+}
+
+.overscroll-y-none {
+  overscroll-behavior-y: none;
+}
+
+.overscroll-x-auto {
+  overscroll-behavior-x: auto;
+}
+
+.overscroll-x-contain {
+  overscroll-behavior-x: contain;
+}
+
+.overscroll-x-none {
+  overscroll-behavior-x: none;
+}
+
 .p-0 {
   padding: 0;
 }