Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add a class to the HTML <body> tag with React?

I'm making a modal in my React project that requires a class to be added to the body when the modal is open and removed when it is closed.

I could do this the old jQuery way by running some vanilla JavaScript which adds / removes a class, however this doesn't feel like the normal React philosophy.

Should I instead setState on my top level component to say whether the modal is open or closed? Even if I did this, as it's rendered into the div on the page it's still a side-effect to edit the body element, so is there any benefit for this extra wiring?

like image 407
Evanss Avatar asked Dec 08 '17 02:12

Evanss


People also ask

Can you add class to body HTML?

We used the add() method to add a class on the body object. We can access the body element on the document object. If the class is already present on the body element, it won't get added twice. You can pass as many classes to the add() method as necessary.

How do I add a class to my body on NextJS?

If you want to add a class ( className ) to the body tag of a a NextJS page, you'll need to add it via JavaScript in the useEffect (or componentDidMount if you're using class-based components) Lifecycle function. This adds TailWindCSS's font-light and text-gray-700 classes to the body tag.

Can we add class to React fragment?

If you need to add a className there, it's clear that either you add a dom element in this case another div or add the className to its parent. Show activity on this post. Using Fragment means not adding an extra node to DOM. If you want to assign a className to a node then you'll have to use div .


4 Answers

TL;DR use document.body.classList.add and document.body.classList.remove

I would have two functions that toggle a piece of state to show/hide the modal within your outer component.

Inside these functions I would use the document.body.classList.add and document.body.classList.remove methods to manipulate the body class dependant on the modal's state like below:

openModal = (event) => {
  document.body.classList.add('modal-open');
  this.setState({ showModal: true });
}
hideModal = (event) => {
  document.body.classList.remove('modal-open');
  this.setState({ showModal: false });
}
like image 104
Sam Logan Avatar answered Oct 19 '22 15:10

Sam Logan


With the new React (16.8) this can be solved with hooks:

import {useEffect} from 'react';

const addBodyClass = className => document.body.classList.add(className);
const removeBodyClass = className => document.body.classList.remove(className);

export default function useBodyClass(className) {
    useEffect(
        () => {
            // Set up
            className instanceof Array ? className.map(addBodyClass) : addBodyClass(className);

            // Clean up
            return () => {
                className instanceof Array
                    ? className.map(removeBodyClass)
                    : removeBodyClass(className);
            };
        },
        [className]
    );
}

then, in the component

export const Sidebar = ({position = 'left', children}) => {
    useBodyClass(`page--sidebar-${position}`);
    return (
        <aside className="...">
            {children}
        </aside>
    );
};
like image 29
Lukas Kral Avatar answered Oct 19 '22 14:10

Lukas Kral


Actually you don't need 2 functions for opening and closing, you could use document.body.classList.toggle

const [isOpen, setIsOpen] = useState(false)
useEffect(() => {
  document.body.classList.toggle('modal-open', isOpen);
},[isOpen])
    
<button onCLick={()=> setIsOpen(!isOpen)}>Toggle Modal</button>
like image 22
Bojan Mitic Avatar answered Oct 19 '22 15:10

Bojan Mitic


Like what @brian mentioned, try having a top-level container component that wraps around your other components. (assuming you're not using redux in your app)

In this top-level component:

  1. Add a boolean state (eg. modalOpen) to toggle the CSS class
  2. Add methods (eg. handleOpenModal & handleCloseModal) to modify the boolean state.
  3. Pass the methods created above as props into your <Modal /> component
like image 29
JustinToh Avatar answered Oct 19 '22 13:10

JustinToh