delmin
delmin

Reputation: 2690

disable scrolling on specific page

Is there any way to disable scroll on one single page? I tried to set overflow: hidden on the specific page but that didn't work. I have to set it on the body in index.css to make it work but that obviously disable scroll on all pages. So the only way to do it that comes to my mind is to set CSS class conditionally on the body. Is there any way to conditionally set CSS class in index.js based on the value from a redux store or is there any other way?

my index.js

import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter} from 'react-router-dom'
import {Provider} from 'react-redux'
import {createStore,applyMiddleware,compose,combineReducers} from "redux";
import thunk from 'redux-thunk'
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import authReducer from './store/reducers/auth'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

const rootReducer = combineReducers({
   auth: authReducer
})

const store = createStore(rootReducer,
   composeEnhancers(applyMiddleware(thunk)));

const app =(
   <Provider store={store}>
      <BrowserRouter>
         <App/>
      </BrowserRouter>
   </Provider>
)

ReactDOM.render(
  <React.StrictMode>
     {app}
  </React.StrictMode>,
  document.getElementById('root')
);
serviceWorker.unregister();

Upvotes: 7

Views: 8589

Answers (6)

Yilmaz
Yilmaz

Reputation: 49182

I use body-scroll-lock npm package:

import {disableBodyScroll,enableBodyScroll,clearAllBodyScrollLocks} from "body-scroll-lock"

const YourPage=(props)=>{
     const ref=useRef(null)

     useEffect(() => {
         if (ref.current) {
             // you might add a condition to lock the scroll
             if (conditionIsTrue) {
                   disableBodyScroll(ref.current)
             } else {
             enableBodyScroll(ref.current)
                }
             }
             return () => {
                  clearAllBodyScrollLocks()
                   }    
      },[addDependencyHere])         

     return(
       <div ref={ref}>
       ....
       </>
     )
}
  • from the above npm package's documentation, you can also use this approach with vanilla js. It is not recommended to access document object in react.js directly

       document.body.ontouchmove = (e) => { 
           e.preventDefault(); 
           return false;
    
  • on touch screen devices you can set this css class conditionally to prevent scrolling

    touch-action:none
    

Upvotes: 0

Austin Jerry
Austin Jerry

Reputation: 161

Adding to Luke Storry's and midnightgamer's amazing answer. You can use a custom react hook with useEffect instead of having to add document.body.style.overflow='auto' in every page to re-enable scroll.

import { useEffect } from 'react'

const useOverFlowHidden = () => {
    useEffect(() => {
        document.body.style.overflow = 'hidden'

        return () => {
            document.body.style.overflow = 'auto' // cleanup or run on page unmount
        }
    }, [])
}

export default useOverFlowHidden

Usage:

const Page = () => {
    useOverFlowHidden(); // use on pages you want to disable overflow/scroll
    return <></>;
}

Upvotes: 1

midnightgamer
midnightgamer

Reputation: 454

A simple solution might be to define a specific class to apply overflow: hidden and apply it on the document. body whenever you want and remove the class when you leave the page.

.overflow-hidden {
   overflow: hidden;
}

Attach class on the body in the specific page and remove when you live the page, so it won't affect other pages

useEffect(() => {
        document.body.classList.add("overflow-hidden");
        return () => {
            document.body.classList.remove("overflow-hidden");
        };
 }, []);

This will simply remove the class from the body when you leave the page.

Upvotes: 1

Luke Storry
Luke Storry

Reputation: 6702

If you wanted to set a style on body, you can just run the below code on the page, which will disable scrolling.

document.body.style.overflow='hidden'

Then to re-enable:

document.body.style.overflow='auto'

Only downside is that is isn't very React-like.

Upvotes: 8

Jax-p
Jax-p

Reputation: 8531

Simple solution might be to define specific class to apply overflow: hidden and apply it on document.body whenever you want (for example after explicit component mount).

.overflow-hidden {
   overflow: hidden;
}

On mount of specific page call:

document.body.classList.add("overflow-hidden");

or you can directly assign property

document.body.style.overflow = "hidden";

Upvotes: 5

Luke Storry
Luke Storry

Reputation: 6702

You can wrap your component in another div, and give that wrapper div the overflow:hidden; style, possibly along with a max-height: 70vh; to make sure it doesn't go over the end of the page.

div {
  padding: .5rem;
  margin: .5rem
}

.no-scroll-wrapper {
  max-height: 70vh;
  overflow: hidden;
  background-color: darkgrey;
  padding: 1rem;
}

.large-inner {
  height: 1000px;
  background-color: grey
}
<body>
  <div class="no-scroll-wrapper">
    wrapper element disables scrolling
    <div class="large-inner">
      Content here, very long div, but you can't see the end of it.
    </div>
  </div>
  </body

Upvotes: 2

Related Questions