4

When I route my app to another component by using react-router-dom, the CSS doesn't change.

This is a minimalistic version of the code to demonstrate

App.js

import React from 'react';
import Home from './Home';

function App() {
    return (
      <div>
        <Home></Home>
      </div>
    );
}

export default App;

Home.js

import React from 'react';
import './Home.css';

const Home = () => {
    return (
        <h1>Home</h1>
    );
}

export default Home;

Home.css

body {
    background-color: blue;
}

Dashboard.js

import React from 'react'; import './Dashboard.css';

import React from 'react';
import './Dashboard.css';

const Dashboard = () => {
    return (
        <div className='content'>
            <h1>Dashboard</h1>
        </div>
    );
}

export default Dashboard;

Dashboard.css

.content {
    display: flex;
    align-content: center;
    align-items: center;
}

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import Dashboard from './Dashboard';
import * as serviceWorker from './serviceWorker';
import { BrowserRouter as Router, Route } from 'react-router-dom';

ReactDOM.render(
    <Router>
        <div>
        <Route exact path='/' component={App} />
        <Route path='/dashboard' component={Dashboard} />
        </div>
    </Router>, document.getElementById('root'));

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: ...
serviceWorker.unregister();

When I do /dashboard, it loads the Dashboard component, but it keeps the previous CSS that was loaded from the Home component that resides the App component. The background stays blue. I want that when I route to another component because I changed the URL, it loads whatever CSS that new component has attached to it and gets rid of whatever CSS was before. Is that possible?

Edit: I have made an example in CodeSandbox to illustrate. It's a little different from the code above due to the limitations of the playground, but the functionality is the same.

Edit frosty-cerf-s3dl3

From what can be seen, importing as a module ends up importing it globally. If we comment the line import Home from "./Home"; the blue background disappears. Just importing the component, imports the whole CSS despite the CSS being imported in a modular way. I'm not sure if I am missing something.

Edit 2:

Here are the different solutions I tried:

  1. CSS Modules, but the body style was still globally loaded.

  2. Styled components don't let me modify the body or html selectors CSS. They require me to create a <div> element and then have that element span the whole body which I would style as if it was the body. Which is a workaround I don't want to use because for that I rather use CSS Modules for the whole body spanning .

  3. Inline styling also doesn't let me modify the body or html selectors CSS. I would also need to use a workaround like a body spanning <div> as in Styled components.

5
  • 1
    i think you need the <Switch><Router /></Switch> so only a single route will be rendered at a time Commented Dec 20, 2019 at 0:41
  • Yeah, you're going to want the Switch component, otherwise the / component and the /dashboard component will both be rendered. Although I don't believe this is relevant to the styling issue. Commented Dec 20, 2019 at 1:01
  • CSS is not stateful. You need to namespace your CSS to only style component elements you want to style. Commented Dec 20, 2019 at 1:07
  • I used <Router><Switch><Route ....>...</Route></Switch></Router>, because it errored out saying I should not use Switch outside of Router, but it still loads the Home blue background when I'm on the Dashboard. @AlexW by namespacing you mean I will have to use SASS or LESS? Commented Dec 20, 2019 at 2:03
  • No I mean it's normally a convention to add a class to your App component and then select/style children using the top level selector, e.g. <App className="App" /> and then .App { background-color: #000000; } .App h1 { color: green; }, etc. SASS or LESS would make it easier to manage due to mixins. Commented Dec 20, 2019 at 20:29

3 Answers 3

3

The problem

When you import a css like you're doing here

import './Home.css';

you're importing it in a global scope, which means it will not disappear once imported.


The solutions

CSS Modules

What you want is either CSS Modules, which is used like this:

import styles from './Home.css';

<a className={styles.myStyleClass}>Hello</a>

Styled components

or a CSS-in-js framework such as styled components which is used like this:

import styled from 'styled-components';

const MyStyledElement = styled.a`
    color: blue;
`;

<MyStyledElement>Hello</MyStyledElement>

Regular objects / inline styling

or just "regular" CSS-in-js like:

const myStyle = {
    color: blue;
}

<a style={myStyle}>Hello</a>

There are plenty of options when it comes to styling, these alternatives are popular ones that I encourage you to explore and see which you enjoy.

Sign up to request clarification or add additional context in comments.

2 Comments

A quick question. Does CSS Modules really work for scoping the css used when a component is loaded? I tried it, but doing import styles from './Home.css'; loads it globally as well. Even if I don't use the style variable for anything, the background of the body is still blue when navigating to other routes. I just found a similar question, but like the OP, it didn't work for me. stackoverflow.com/questions/45228589/…
I have added a CodeSandbox sample to my question to show what I am getting when using CSS Modules. I am not sure if I am missing something.
0

After doing some more tests I have concluded that as of now it is not possible to change whatever CSS styles have been applied to a <body> or <html> selector in an React SPA when a CSS file is already loaded and one uses React Router to render other components. I still appreciate the answers and the time taken to help me find a solution. They are still valid answers if we are not talking about the <body> or <html> node in an HTML document. From them I learned about other ways to use CSS in React. I modified the original post with the solutions I tried.

What ended working was modifying the DOM styles with JavaScript whithin the component itself.

Home.js

import React from "react";

const Home = () => {
  // Modify the DOM Styles with JavaScript
  document.body.style.backgroundColor = "blue";

  // Or uncomment below to modify the
  // document root background color
  // which in this case would be <html>

  //document.bgColor = "blue";

  // Or modify the root tag style of the document instead of the
  // <body> (<html> in this case)

  //document.documentElement.setAttribute('style', 'background-color: green');

  return (
    <div>
      <h1>Home</h1>
      <form action="/dashboard">
        <input type="submit" value="Go to Dashboard" />
      </form>
    </div>
  );
};

export default Home;

Here is a working example:

Edit elastic-dawn-4stoi

Comments

0

The problem I faced was that I used the same className for both components (Login and Register), copied the styles in css and made some changes which conflicted. When I set different classNames then it fixed the issue.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.