Resolving the Material-UI NextJS Button Styling Dilemma

I've encountered an issue with the styling of a few buttons in JS. When I apply a styling class using className, the formatting works fine on the initial render but loses its styling on subsequent refreshes. This problem is specific to two individual buttons. After trying various troubleshooting methods, I discovered that switching to SX instead of classNames resolves the issue and the styling persists even after refreshing. In the code below, one button retains its styles while the other does not upon refreshing. I'm puzzled at this point as I've extensively searched through forums and found mentions of NextJs potentially requiring additional configuration in the _document and _app files for it to function properly. However, I used the NextJs Material UI boilerplate from Git, so I doubt that is causing the problem.

Code:

import React from 'react'

import { AppBar, Toolbar, alpha } from "@mui/material";
import Button from '@mui/material/Button'
import ButtonBase from '@mui/material/ButtonBase';
import { styled } from '@mui/material/styles';
import Typography from '@mui/material/Typography';
import InputBase from '@mui/material/InputBase';
import SearchIcon from '@mui/icons-material/Search';
import AddIcon from '@mui/icons-material/Add';
import { makeStyles } from '@mui/styles'

const useStyles = makeStyles(theme => ({

    button: {
        ...theme.typography.mainmenu,
        borderRadius: "40px",
        width: "230px",
        height: "130px",
        marginLeft: "30px",
        alignItem: "center",
        "&:hover": {
            backgroundColor: theme.palette.secondary
        },
        [theme.breakpoints.down("sm")]: {
            width: '100% !important', // Overrides inline-style
            height: 100
        },
    },

}))
/*Image Button Styling Begins*/
const images = [
    {
        url: '/assets/breakfastMenu.jpg',
        title: 'Breakfast',
        width: '20%',
    },
    {
        url: '/assets/steak.jpg',
        title: 'Mains',
        width: '20%',
    },
    {
        url: '/assets/desserts.jpg',
        title: 'Desserts',
        width: '20%',
    },
];
const Image = styled('span')(({ theme }) => ({
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'space-between',
    color: theme.palette.common.primary,
}));

const ImageButton = styled(ButtonBase)(({ theme }) => ({
    position: 'relative',
    height: 150,
    [theme.breakpoints.down('sm')]: {
        width: '100% !important', // Overrides inline-style
        height: 100,
    },
    '&:hover, &.Mui-focusVisible': {
        zIndex: 1,
        '& .MuiImageBackdrop-root': {
            opacity: 0.15,
        },
        '& .MuiImageMarked-root': {
            opacity: 0,
        },
        '& .MuiTypography-root': {
            border: '4px solid currentColor',
        },
    },
}));

const ImageSrc = styled('span')({
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    backgroundSize: 'cover',
    backgroundPosition: 'center 40%',
});
const ImageBackdrop = styled('span')(({ theme }) => ({
    position: 'absolute',
    left: 0,
    right: 0,
    top: 0,
    bottom: 0,
    backgroundColor: theme.palette.common.black,
    opacity: 0.4,
    transition: theme.transitions.create('opacity'),
}));

const ImageMarked = styled('span')(({ theme }) => ({
    height: 3,
    width: 18,
    backgroundColor: theme.palette.common.white,
    position: 'absolute',
    bottom: -2,
    left: 'calc(50% - 9px)',
    transition: theme.transitions.create('opacity'),
}));
/*Image Button Styling Ends*/

const Search = styled('div')(({ theme }) => ({
    position: 'relative',
    borderRadius: theme.shape.borderRadius,
    backgroundColor: alpha(theme.palette.common.white, 0.15),
    '&:hover': {
        backgroundColor: alpha(theme.palette.common.white, 0.25),
    },
    marginLeft: 0,
    width: '100%',
    [theme.breakpoints.up('sm')]: {
        marginLeft: theme.spacing(1),
        width: 'auto',
    },
}));

const SearchIconWrapper = styled('div')(({ theme }) => ({
    padding: theme.spacing(0, 2),
    height: '100%',
    position: 'absolute',
    pointerEvents: 'none',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
}));

const StyledInputBase = styled(InputBase)(({ theme }) => ({
    color: 'inherit',
    '& .MuiInputBase-input': {
        padding: theme.spacing(1, 1, 1, 0),
        // vertical padding + font size from searchIcon
        paddingLeft: `calc(1em + ${theme.spacing(4)})`,
        transition: theme.transitions.create('width'),
        width: '100%',
        [theme.breakpoints.up('sm')]: {
            width: '12ch',
            '&:focus': {
                width: '20ch',
            },
        },
    },
}));


const Header = () => {
    const classes = useStyles();
    return (<React.Fragment>
        <AppBar position="sticky" className={classes.appBar}>
            <Toolbar disableGutters>

                {images.map((image) => (
                    <ImageButton
                        focusRipple
                        key={image.title}
                        style={{
                            width: image.width,
                        }}
                    >
                        <ImageSrc style={{
                            backgroundImage: `url(${image.url})`
                        }} />
                        <ImageBackdrop className="MuiImageBackdrop-root" />
                        <Image>
                            <Typography
                                component="span"
                                variant="subtitle1"
                                color="white"
                                fontWeight="bold"

                                sx={{
                                    position: 'relative',
                                    p: "7em",
                                    pt: "2em",
                                    pb: (theme) => `calc(${theme.spacing(1)} + 6px)`,
                                }}
                            >
                                {image.title}
                                <ImageMarked className="MuiImageMarked-root" />
                            </Typography>
                        </Image>
                    </ImageButton>
                ))}
                <Button size="large" variant="contained" color="secondary"
                    startIcon={<AddIcon />}
                    sx={{
                        borderRadius: "40px", borderRadius: "40px",
                        width: "230px",
                        height: "130px",
                        marginLeft: "30px",
                        alignItem: "center",
                    }} >Add A recipe</Button>
                <Button size="large" variant="contained" color="secondary" className={classes.button}>Meals for the Week</Button>
                <Search>
                    <SearchIconWrapper>
                        <SearchIcon />
                    </SearchIconWrapper>
                    <StyledInputBase
                        placeholder="Search…"
                        inputProps={{ 'aria-label': 'search' }}
                    />
                </Search>
            </Toolbar>
        </AppBar>

    </React.Fragment >
    )
}

export default Header

https://i.stack.imgur.com/Cckj8.jpg

Answer №1

To ensure proper styling with NextJS server side rendering, it's crucial to add configuration to the _document.tsx file. This is necessary because certain styles need to be injected into the DOM for effective rendering.

The MUI documentation explains how you can utilize the ServerStyleSheets feature to manage server side rendering correctly.

Below is an example of the code found in my _document.tsx:

import React from 'react';
import Document, { Html, Main, NextScript } from 'next/document';
import { ServerStyleSheets } from '@mui/styles';

export default class MyDocument extends Document {
    render() {
        return (
            <Html>
                <body>
                    <Main />
                    <NextScript />
                </body>
            </Html>
        );
    }
}

MyDocument.getInitialProps = async (ctx) => {
    const sheets = new ServerStyleSheets();
    const originalRenderPage = ctx.renderPage;

    ctx.renderPage = () =>
        originalRenderPage({
            enhanceApp: (App) => (props) => sheets.collect(<App {...props} />)
        });

    const initialProps = await Document.getInitialProps(ctx);

    return {
        ...initialProps,
        styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()]
    };
};

For more details on this topic, refer to the Server rendering - MUI docs.

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

It is not possible to alter or manipulate dynamic content received from an Ajax/JSON response when creating a dynamic PHP form

I am in need of a dynamic form that functions as follows: Upon clicking the "ADD" button, a new <div> element should appear for selecting a package. Based on the selected package, the row should change its color by adding or removing certain classe ...

Experimenting with enzyme to test React portals

I've run into a challenge while attempting to write tests for a modal component using React fiber's portal. The issue arises because my modal is mounted to a domNode on the root of the <body />, but since that domNode doesn't exist dur ...

Edge and Internet Explorer fail to recognize the :focus CSS selector

I am utilizing CSS to make our placeholders jump up when clicked inside, but Edge is not recognizing the CSS. It works fine on every other browser except for Edge. I've tried various solutions but none seem to work on Edge. Any thoughts on what might ...

Odd behavior observed in the Android browser while choosing input fields

When stacking modal elements in the Android Webkit browser (tested on versions 2.2, 2.3, and 3.0), strange behavior seems to occur. Take this example: Here, I have a jQuery UI date picker with z-index 200, a gray overlay div covering the entire document w ...

What sets apart the `className` prop from the innovative MUI system utility `sx` prop?

Lately, I've primarily relied on the makeStyles hook to style my material-ui components. It's simple, modular, and efficient. In Material-UI v5, they introduced the new sx prop which shows promise, but it comes with a performance tradeoff as men ...

Server Error 502 Encountered with Nextjs Image Component

next/image seems to be causing a 502 gateway error on the server. After checking with the devtool network, it appears that it is trying to fetch images from a third party (themoviedb) API. These images are not loading correctly, although they work fine on ...

Encountering an issue with postman where properties of undefined cannot be read

I am facing an issue while trying to create a user in my database through the signup process. When I manually enter the data in the create method, it works fine as shown below: Note: The schema components are {userName:String , number:String , email:Stri ...

Is it possible to pass a useState function to a component during its initialization?

Currently, I am utilizing the useState hook to effectively handle the rendering of components on the screen. My goal is to initialize it with a component while passing in the useState function to set the screen within the component. Below is my App.js fil ...

Unusual CSS rendering hiccup

Using jQuery, I am manipulating the display of an <a> element. Depending on certain keypress events, it adds or removes a class from an <input> element (which controls the display) that is related as a sibling to the mentioned <a>. The i ...

What is the process for creating unit tests that accommodate various screen sizes?

I have a dilemma with displaying two buttons based on the size of the screen (one for medium screens and another for other screens). I am utilizing Material UI's MediaQuery and theme.breakpoints to define the screen size in my UI code. The code is wri ...

Encountering an issue with React and Material-UI where the MuiDialog-root appears to become unresponsive

While using React with MaterialUI, I'm encountering an issue where a div element remains stuck on the screen after closing a MUI dialog: <div class="MuiBackdrop-root" aria-hidden="true" style="opacity: 0; transition: opacity 195ms cubic-bezier(0.4 ...

How to conceal table cells on Safari 5?

My code works on Firefox and IE, but not on Safari. Here's an example: <table> <thead> <tr> <th style="display: none;">hi</th> </tr> </thead> <tr class="someClass"> <td style= ...

Several radio buttons and their corresponding labels are shown on a single line inside a nested div container

Upon stumbling across this post, I realized it perfectly aligns with my current goal: Radio Button and Label to display in same line. However, the challenge persists... The layout I currently have (first 3 columns) differs from what I aspire to achieve (l ...

Hide bootstrap card on smaller screens such as sm and md

Utilizing the Bootstrap 4.1 card component, I showcase categories within the right sidebar - check out a sample image of the card here: Card example image; When viewing on smaller screens, it's preferable to collapse this large card as shown in this ...

Nested Columns in Material Table

Could a nested column table be created using the material-table library? The desired final outcome I am aiming for ...

Compilation failure resulting from core UI build in React js

I have recently transitioned my domain to React Js and am in the process of learning. I have been working on creating an admin panel using Core UI Reactjs components, however I keep encountering an error that says "This error occurred during the build ti ...

When I try to refresh the page, React is unable to show a random selection of listings using the aggregate

I'm currently working on a recipe website where I want to display the recipes in random order every time the page is reloaded. However, I seem to be facing an issue where it only shows "no recipe found" message. I specifically need the recipes to appe ...

Something strange happening with the HTML received after making a jQuery AJAX request

My PHP form handler script echoes out some HTML, which is called by my AJAX call. Below is the jQuery code for this AJAX call: $(function() { $('#file').bind("change", function() { var formData = new FormData(); //loop to add ...

Tips for including HTML in a JSON request in ReactJS

Upon sending the request as shown below, the response was successfully received. { "contractId": "siva8978", "html": "<p>PREFERENCE SHAREHOLDER AGREEMENTTHIS AGREEMENT is made on the&nbsp;$$Contract Start Date$$ BETWEEN&nbsp;CRADLE WEALTH ...

Trouble with CSS3 Perspective rendering issue

Here's a simple example showcasing the use of CSS3 Perspective property to create a 3D side flip effect. However, this basic demonstration does not seem to achieve the desired outcome. <html> <head> <style> .div1{height:300px; ...