{"id":5477,"date":"2021-09-17T02:00:00","date_gmt":"2021-09-17T00:00:00","guid":{"rendered":"https:\/\/alvarotrigo.com\/epa\/prevent-scroll-on-scrollable-element-js\/"},"modified":"2024-02-05T20:06:56","modified_gmt":"2024-02-05T19:06:56","slug":"prevent-scroll-on-scrollable-element-js","status":"publish","type":"post","link":"https:\/\/alvarotrigo.com\/blog\/prevent-scroll-on-scrollable-element-js\/","title":{"rendered":"Prevent Scroll On Scrollable Elements [JS &#038; CSS]"},"content":{"rendered":"<p>If you ever need to temporally <strong>disable scrolling<\/strong> on a specific scrollable element, then you will need to use JavaScript or CSS for it. Depending on your use case, you can choose between JavaScript and CSS solutions. Although in general terms the CSS solution is the most adopted one, JavaScript offers you a bit more of control and flexibility and allows you to decide how exactly you want to <strong>stop the scrolling<\/strong>.<\/p>\n<h2 class=\"wp-block-heading\" id=\"1.-cancelling-scroll-using-javascript\">1. Cancelling scroll using JavaScript<\/h2>\n<p>One of the options is to listen to the <code>wheel<\/code> event on the element you want to prevent the scrolling and then prevent the default behavior as well as stopping the propagation and returning a <code>false<\/code> value.<\/p>\n<p>Something as simple as this, where <code>#scrollable<\/code> would be the ID of our scrollable element.<\/p>\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'#scrollable'<\/span>).addEventListener(<span class=\"hljs-string\">'wheel'<\/span>, preventScroll, {<span class=\"hljs-attr\">passive<\/span>: <span class=\"hljs-literal\">false<\/span>});\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">preventScroll<\/span>(<span class=\"hljs-params\">e<\/span>)<\/span>{\n    e.preventDefault();\n    e.stopPropagation();\n\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Notice as well that we are using the option <code>{passive: false}<\/code> on the event listener. This is actually because we have to tell browsers that, eventually, we might call <code>preventDefault<\/code> and cancel the default behavior. This way the browser is aware of it and can decide how to treat the event. You can read more about it on <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/EventTarget\/addEventListener\" target=\"_blank\" rel=\"noopener nofollow\">the docs<\/a>.<\/p>\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n<p>If you need to provide support for IE 11 you might need to add a fallback for the passive event param as it is not supported check if the passive event is supported.<\/p>\n<\/blockquote>\n<p>Now, what if we want to enable or disable this dynamically? Here&#8217;s an example with a couple of buttons, one to disable the scroll and another one to enable it:<\/p>\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_qBjpgjV\" data-src=\"\/\/codepen.io\/anon\/embed\/qBjpgjV?height=450&amp;theme-id=1&amp;slug-hash=qBjpgjV&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed qBjpgjV\" title=\"CodePen Embed qBjpgjV\" class=\"cp_embed_iframe lazyload\" style=\"width:100%;overflow:hidden\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" data-load-mode=\"1\">CodePen Embed Fallback<\/iframe><\/div>\n\n<p>If you want to apply it to multiple elements, it is as easy as iterating over them and applying them to the same function.<\/p>\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'.scrollable'<\/span>).forEach(<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span>(<span class=\"hljs-params\">item<\/span>)<\/span>{\n    item.addEventListener(<span class=\"hljs-string\">'wheel'<\/span>, preventScroll);\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now, take a look at the CSS way because the JS way can get a bit more complicated if we take into account keyboard and touch scrolling.<\/p>\n<h2 class=\"wp-block-heading\" id=\"2.-disabling-scroll-with-only-css\">2. Disabling scroll with only CSS<\/h2>\n<p>There&#8217;s another way to disable scrolling that is commonly used when opening modals or scrollable floating elements. And it is simply by adding the CSS property <code>overflow: hidden;<\/code> on the element you want to prevent the scroll.<\/p>\n<p>It is clearly the easiest solution if you want to disable scroll no matter what triggers it (mouse, keyboard, or touch), but at the same time, it won&#8217;t give you the flexibility of choosing what to disable and what not.<\/p>\n<p>There&#8217;s a couple of differences with the previous way. They can be good for you, or not, depending on your use case:<\/p>\n<ul class=\"wp-block-list\">\n<li>\n<p>It will also disable the keyboard scrolling too. So, you won&#8217;t be able to move up or down by using the keyboard arrows and space bar, etc.<\/p>\n<\/li>\n<li>\n<p>It will not allow you to scroll up\/down by selecting text.<\/p>\n<\/li>\n<li>\n<p>It will disable touch scroll too.<\/p>\n<\/li>\n<li>\n<p>It might also prevent scrolling using &#8220;the third button&#8221; of the mouse, which is pressing the mousewheel while dragging the mouse. (If anyone can verify this for me that&#8217;d be great, as I don&#8217;t have a mouse to test it at the moment \ud83d\ude42 )<\/p>\n<\/li>\n<\/ul>\n<p>So, how do we do it? We create a class that we will toggle whenever we need it and that all it does is preventing the scroll on the element we apply it.<\/p>\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css\"><span class=\"hljs-selector-class\">.disable-scroll<\/span>{\n  <span class=\"hljs-attribute\">overflow-y<\/span>: hidden;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Then, with JavaScript we simply add or remove it when we want:<\/p>\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\">\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">disable<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>{\n  <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'.scrollable'<\/span>).classList.add(<span class=\"hljs-string\">'disable-scroll'<\/span>);\n}\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">enable<\/span>(<span class=\"hljs-params\"><\/span>)<\/span>{\n  <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'.scrollable'<\/span>).classList.remove(<span class=\"hljs-string\">'disable-scroll'<\/span>);\n}\n\n<span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'#prevent'<\/span>).addEventListener(<span class=\"hljs-string\">'click'<\/span>, disable);\n<span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'#allow'<\/span>).addEventListener(<span class=\"hljs-string\">'click'<\/span>, enable);\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Here&#8217;s a working example:<\/p>\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_ExXorwX\" data-src=\"\/\/codepen.io\/anon\/embed\/ExXorwX?height=450&amp;theme-id=1&amp;slug-hash=ExXorwX&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed ExXorwX\" title=\"CodePen Embed ExXorwX\" class=\"cp_embed_iframe lazyload\" style=\"width:100%;overflow:hidden\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" data-load-mode=\"1\">CodePen Embed Fallback<\/iframe><\/div>\n\n<h2 class=\"wp-block-heading\" id=\"3.-preventing-keyboard-scroll-using-javascript\">3. Preventing keyboard scroll using JavaScript<\/h2>\n<p>If you decide to go for the JS solution, then you might also want to disable scroll through the keyboard.<\/p>\n<p>In this case, we simply have to listen to the <code>keydown<\/code> event and prevent the default behavior when we detect they are pressing any key that can trigger a scroll movement, such as the keyboard arrows, spacebar, shift+space bar, pageup, pagedown etc.<\/p>\n<p>Here&#8217;s the code:<\/p>\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-built_in\">document<\/span>.addEventListener(<span class=\"hljs-string\">'keydown'<\/span>, preventKeyBoardScroll, <span class=\"hljs-literal\">false<\/span>);\n\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">preventKeyBoardScroll<\/span>(<span class=\"hljs-params\">e<\/span>) <\/span>{\n  <span class=\"hljs-keyword\">var<\/span> keys = &#91;<span class=\"hljs-number\">32<\/span>, <span class=\"hljs-number\">33<\/span>, <span class=\"hljs-number\">34<\/span>, <span class=\"hljs-number\">35<\/span>, <span class=\"hljs-number\">37<\/span>, <span class=\"hljs-number\">38<\/span>, <span class=\"hljs-number\">39<\/span>, <span class=\"hljs-number\">40<\/span>];\n  <span class=\"hljs-keyword\">if<\/span> (keys.includes(e.keyCode)) {\n    e.preventDefault();\n    <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-literal\">false<\/span>;\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>And here&#8217;s the example:<\/p>\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_abwEXaV\" data-src=\"\/\/codepen.io\/anon\/embed\/abwEXaV?height=450&amp;theme-id=1&amp;slug-hash=abwEXaV&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed abwEXaV\" title=\"CodePen Embed abwEXaV\" class=\"cp_embed_iframe lazyload\" style=\"width:100%;overflow:hidden\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" data-load-mode=\"1\">CodePen Embed Fallback<\/iframe><\/div>\n\n<h2 class=\"wp-block-heading\" id=\"4.-preventing-touch-scroll-using-javascript\">4. Preventing touch scroll using JavaScript<\/h2>\n<p>And of course, we can&#8217;t forget about the touch scroll. The CSS solution seems to make things like this much easier for us, but if we need total control over what we allow users to do and what not, then probably the JavaScript version is the way to go.<\/p>\n<p>Regarding touch events, this is pretty similar to <strong>canceling the scroll<\/strong> for the wheel event.<\/p>\n<p>We simply have to add the exact same function on a <code>touchmove<\/code> event listener:<\/p>\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">var<\/span> scrollable = <span class=\"hljs-built_in\">document<\/span>.querySelector(<span class=\"hljs-string\">'.scrollable'<\/span>);\nscrollable.addEventListener(<span class=\"hljs-string\">'touchmove'<\/span>, disable, {<span class=\"hljs-attr\">passive<\/span>: <span class=\"hljs-literal\">false<\/span>});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n<div class=\"wp-block-cp-codepen-gutenberg-embed-block cp_embed_wrapper\"><iframe id=\"cp_embed_yLXpwLb\" data-src=\"\/\/codepen.io\/anon\/embed\/yLXpwLb?height=450&amp;theme-id=1&amp;slug-hash=yLXpwLb&amp;default-tab=css,result\" height=\"450\" scrolling=\"no\" frameborder=\"0\" allowfullscreen allowpaymentrequest name=\"CodePen Embed yLXpwLb\" title=\"CodePen Embed yLXpwLb\" class=\"cp_embed_iframe lazyload\" style=\"width:100%;overflow:hidden\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" data-load-mode=\"1\">CodePen Embed Fallback<\/iframe><\/div>\n\n<h2 class=\"wp-block-heading\" id=\"5.-using-a-npm-module-to-disable-scroll\">5. Using a npm module to disable scroll<\/h2>\n<p>You will also find there are a few components and modules out there that give you this feature out of the box.<\/p>\n<p>Some only apply to the whole document while others allow you to be applied to specific scrollable elements.<\/p>\n<p>Here&#8217;s a few I found:<\/p>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/github.com\/gilbarbara\/disable-scroll\" target=\"_blank\" rel=\"noopener nofollow\">https:\/\/github.com\/gilbarbara\/disable-scroll<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/FL3NKEY\/scroll-lock\" target=\"_blank\" rel=\"noopener nofollow\">https:\/\/github.com\/FL3NKEY\/scroll-lock<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/realjoshharrison\/jquery-disablescroll\" target=\"_blank\" rel=\"noopener nofollow\">https:\/\/github.com\/realjoshharrison\/jquery-disablescroll<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/davidtheclark\/no-scroll\" target=\"_blank\" rel=\"noopener nofollow\">https:\/\/github.com\/davidtheclark\/no-scroll<\/a><\/li>\n<li><a href=\"https:\/\/github.com\/bameyrick\/prevent-scrolling\" target=\"_blank\" rel=\"noopener nofollow\">https:\/\/github.com\/bameyrick\/prevent-scrolling<\/a><\/li>\n<\/ul>\n<h2 class=\"wp-block-heading\" id=\"related-articles\">Related articles<\/h2>\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/alvarotrigo.com\/blog\/scroll-lock-key\/\">What Is The Scroll Lock key?<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Need to temporally disable scrolling on a specifc scrollable element? Here are 5 ways to do it!<\/p>\n","protected":false},"author":1,"featured_media":5476,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[107,106],"tags":[10,18],"class_list":["post-5477","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-javascript","category-css","tag-javascript","tag-jquery"],"acf":[],"_links":{"self":[{"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/posts\/5477","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/comments?post=5477"}],"version-history":[{"count":2,"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/posts\/5477\/revisions"}],"predecessor-version":[{"id":8940,"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/posts\/5477\/revisions\/8940"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/media\/5476"}],"wp:attachment":[{"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/media?parent=5477"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/categories?post=5477"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alvarotrigo.com\/blog\/wp-json\/wp\/v2\/tags?post=5477"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}