Adding a custom class to the body element for specific routes in Next.js can be achieved by utilizing the features of

I am looking to apply my custom class to certain pages, with the exception of specific routes. For example, all pages should have the class fixed-header, except for the following routes:

/cart/step-1

/login

This class should be added or removed from the body element.

<body className="bg-gray fixed-header"

However, I am unsure how to implement this scenario. Any suggestions?

Answer №1

Start by creating your own custom _document.js and _app.js files within the pages directory.

Here's a handy utility function to check for classes on the body element (to prevent duplicate classes, inspired by @juliomalves):

// ./utils/hasClasses
const hasClasses = () =>
  document.body.classList.contains("bg-gray") &&
  document.body.classList.contains("fixed-header");
export default hasClasses;

Implementing Server-Side Rendering

In the _document.js file, utilize the __NEXT_DATA__ prop to access the current page, verify if the page is in your approved routes, and add appropriate classes to the body element.

import Document, { Html, Head, Main, NextScript } from "next/document";

class MyDocument extends Document {

  // Add more routes here if you wish to apply the same classes  
  allowedRoutes = ["/login", "/cart/step-1"];

  getColor() {
    const { page } = this.props?.__NEXT_DATA__;
    if (this.allowedRoutes.includes(page))
      return "bg-gray fixed-header";
    return "";
  }

  render() {
    return (
      <Html>
        <Head />
        <body className={this.getColor()}>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

This code will execute exclusively on the server side. The classes won't be added to the body during client-side navigation.

Client-Side Rendering Solution

To address the aforementioned issue, apply the same logic found in _app.js within a useEffect hook, ensuring that the appropriate class is added during client-side rendering.

import { useEffect } from "react";
import { useRouter } from "next/router";
import "../styles.css";
import hasClasses from "./utils/hasClasses";

function MyApp({ Component, pageProps }) {

  const { pathname: page } = useRouter();
  const allowedRoutes = ["/login", "/cart/step-1"];

  useEffect(() => {
    if (!hasClasses() && allowedRoutes.includes(page))
      document.body.className += "bg-gray fixed-header";
    else if (hasClasses()) {
      // Eliminate styles on other pages to prevent conflicts.
      // Determine how to handle this based on your needs.
      document.body.classList.remove("bg-gray");
      document.body.classList.remove("fixed-header");
    }
  });
  return <Component {...pageProps} />;
}

export default MyApp;

This approach ensures proper application of classes during client-side navigation on permitted routes. The code within _document.js guarantees that pages rendered on the server are transmitted with correct styling to prevent any visual glitches on the client side.

Answer №2

If you're looking for a simple and efficient solution, this one's for you. Just insert the following code snippet into every component where you need to apply unique classes to the <body> element.

useEffect( () => { document.querySelector("body").classList.add("bg-gray fixed-header") } );

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Multi selection dropdown feature in Angular failing to populate the options

I am working on a small Angular controller that manages a dropdown menu, with the second dropdown menu populating based on the selection made in the first one. Despite my best efforts, I can't seem to populate the dropdown menus with any content from ...

Switch between multiple unordered lists (ul) so that when one list is clicked, the other lists reset to their initial state as though they were never

When I click on the first item in the ul list, it should slideToggle() to show its corresponding items. Similarly, when I click on the second item in the ul list, its items should slideToggle(), but the first ul list remains visible as well. What I am tryi ...

Extracting timestamped text data from a simulated chat interface

I am looking to gather chat data from Twitch clips. These are saved moments from livestreams where viewer reactions are captured. Take a look at this example clip: While I can scrape all the data by watching the video and utilizing query selectors, my goa ...

Ways to update state based on changes in localStorage values

Is there a way to update the state when the value of localStorage changes? For instance, I have a language switch button for French and English. When I click on English, it gets stored in localStorage. How can I ensure that the entire project switches to t ...

How to transfer identification from one AngularJS page to another

I need help figuring out how to retrieve an ID from the list.html page and use that same ID to display corresponding details on the list-detail.html page. I am new to using angularjs and struggling with getting the details based on the ID. Below is my code ...

Error message thrown by Angular JS: [$injector:modulerr] – error was not caught

I have been working on a weather forecasting web application using AngularJS. Here's a snippet of my code: var myApp = angular.module("myApp", ["ngRoute", "ngResource"]); myApp.config(function($routeProvider){ $routeProvider .when('/',{ ...

Guide to connecting to various controllers in Angular

To streamline the process of fetching data from the server and paginating it for all resources, I developed a custom ListCtrl. However, before setting it up, this controller needs to receive certain configurations such as the path to the resource and defau ...

An error occurred during runtime due to a TypeError when trying to execute the 'setItem' function on 'Storage'. The error message indicates that 2 arguments are required for this function, but only 1 argument

Having an issue with the local storage not working and the screen showing up as white in the browser. 5 | const getFromLocalStorage = () => { 6 | if (typeof window !== undefined) { > 7 | const value = localStorage.getItem(& ...

Getting the inner element of a particular child from the parent div using selenium with javascript

<div class="A"> <svg> ... </svg> <button> <svg> ... </svg> </button> <svg> ... </svg> </div> <div class="A"> <svg> ... </svg> <button> ...

Using jQuery's .remove() function removes all of the children from the container, rather than just one at

For my latest project, I am focused on creating a seamless full-page transition using AJAX calls. The challenge I'm facing is removing content from the DOM when loading in a new page. Despite adding a unique class or ID to the element, the .remove() f ...

Despite working smoothly with an HTML form tag, the "req.file" multer is undefined when it comes to HTTP requests from a script

I have created a basic file uploader using multer in Node.js, which works well when uploading files using an html form like this: <form id="uploadForm" enctype="multipart/form-data" method="post"> <input type="file" name="userFile" /> ...

Monitor a nested watch property for potential undefined or default values

Currently tackling an issue in my Vue2 project related to a specific property I'm trying to watch. Here's what the code snippet looks like: watch: { 'car.wheels': function(){ ... } Sometimes, 'wheels' is undefined ...

Angular: Discovering and retrieving all images within a div container

I am on a quest to locate all image tags within a specific div. These image tags are nested within paragraph tags inside the div. I attempted to create a plunkr to accomplish this task, but unfortunately, I haven't had any success yet. If anyone is ab ...

An Ajax call nested within another Ajax call

I've implemented an AJAX request to load my "home" page and "about" page into a designated "container" when a menu link button is clicked on my index.php. Now, I have three links on my "home" page and I want each of these links to open within the same ...

Tips on enclosing <li> elements within <ul> tags

Whenever I trigger the button within the .items class, it generates <li> elements in the following manner: <ul class="items"> <ul class="items"> <li>img1</li> ...

What is the best way to link JavaScript files from a Grails plugin in a separate Grails application?

I have developed a unique plugin that offers multiple Grails controllers and domain objects. Additionally, I have created several AngularJS UI components that I wish to utilize in various other projects. These specific files are located within the web-app ...

Achieve resumable uploads effortlessly with google-cloud-node

While this code works well for regular uploads, I am curious about how the resumable upload feature functions when a user loses connection during a large upload. Does simply setting 'resumable' to true in the writeStream options make it work effe ...

What steps can be taken to enhance the functionality of this?

Exploring ways to enhance the functionality of JavaScript using the underscore library. Any ideas on how to elevate this code from imperative to more functional programming? In the provided array, the first value in each pair represents a "bucket" and the ...

Analyzing the browser's address bar and creating a navigation link derived from it

Is there a way to create a script that can extract information from the address bar? For example, if we have a link like this: We want to be able to take the "page-2011" part and dynamically generate navigation links like this: « <a href="/page-2010 ...

Sharing data from AJAX calls in Vue using vue-resource

After using Vue resource, I'm attempting to create an AJAX call that is based on the data received from a prior AJAX call. I have successfully bound the data fetched from /me to the userDetails prop. However, when trying to pass userDetails.id into t ...