13

I am a beginner to CSS-in-JS and emotion, and trying to port a sass react app to emotion. Right from the start I already have the issue of not knowing how to style the body tag.

Do people generally use document.body.style to do this? I can't find this covered anywhere ...

Suppose I want to port following code to emotion, how would that be accomplished?

$bodyFillColor: rgb(218, 236, 236);

body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  max-width: 100vw;
  background-color: $bodyFillColor;
  .noScroll {
    overflow: hidden;
  }
}

Have any best practices evolved yet that cover this?

David Deprost
  • 4,072
  • 1
  • 20
  • 27
  • I just use document.body.style. Don't fix what isn't broken lol – fig Dec 15 '18 at 17:05
  • But does that allow variables inside the style? If so, could you be so kind as to provide an answer with the full equivalent code? This would be very useful to completely wrap my mind around it! – David Deprost Dec 15 '18 at 17:32
  • Write body css to a variable, create style element, and append it to body. You don't need file.css for that. – A. Meshu Dec 15 '18 at 19:34

3 Answers3

18

With Emotion you can set something up, like the following create-react-app example, to inject global styles:

import React from 'react';
import ReactDOM from 'react-dom';
import { Global, css } from '@emotion/core'

const bodyFillColor = `rgb(218,236,236)`;

class App extends React.Component {
  render() {
    return(
      <div>
        <Global
          styles={css`
            body {
              background: ${bodyFillColor};
              margin: 0;
              padding: 0;
              min-height: '100vh';
              max-width: '100vw';
            }
          `}
        />
        <Global
          styles={{
            'body.noScroll': {
                // Prevent scrolling; conditionally activate this
                // in subcomponents when necessary ...
                overflow: 'hidden',
            },
          }}
        />
      </div>
    );
  }
}

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

This shows an example of injecting a style on the body and also assigning a class to the body that can conditionally be activated later on.

eg.

{this.state.activate && <Global styles={{`stylesetc`}}/>}

https://emotion.sh/docs/globals

Alternative

StyledComponents uses a CSS-in-JS approach and works great with React applications. This is a technique I've used in the past straight from the documentation:

import { createGlobalStyle } from 'styled-components'

const GlobalStyle = createGlobalStyle`
  body {
    color: ${props => (props.whiteColor ? 'white' : 'black')};
  }
`

// later in your app

<React.Fragment>
  <Navigation /> {/* example of other top-level stuff */}
  <GlobalStyle whiteColor />
</React.Fragment>
eagles1283
  • 220
  • 1
  • 9
  • createGlobalStyle used to be injectGlobal, btw – eagles1283 Dec 15 '18 at 19:28
  • Interesting. So I guess this needs to be placed inside an component that goes to the ReactDOM.render() function? Even though this answer is not about emotion, I will upvote because it is the most useful answer yet! Does emotion have something similar? – David Deprost Dec 15 '18 at 19:38
  • Oops, I read it too fast. Emotion has it's own way to do this since it is heavily inspired by styled-components. I'll edit my answer – eagles1283 Dec 15 '18 at 20:30
  • let me know if this clears things up, and I'd appreciate you accepting my answer if it does! Good luck – eagles1283 Dec 15 '18 at 20:36
  • Well, actually, I already read that in the docs, but it's not really clear to me. In React render methods are always inside a component, so is this an emotion-specific global render method then? Would this work with variables? How would my code (see question) that has a variable look like? These docs aren't exactly very elaborate ... – David Deprost Dec 15 '18 at 22:15
  • @DavidDeprost what you've provided is minimal, so specifics have been tough while trying to answer this. I think your question now is mostly about proper React application syntax. – eagles1283 Dec 15 '18 at 22:54
  • @DavidDeprost The render function will usually be wrapped in some class, as per usual. In this case, Emotion is creating what is called a High Order Component(HOC) that helps you not have to worry about writing out too much functionality. I hope you'll accept my answer after I edit for clarity – eagles1283 Dec 15 '18 at 22:56
  • 1
    Thanks a lot for your help. Got it working thanks to you. I made an edit to your answer to complete/improve it. It is now runnable as is. If the edit is ok with you, I'll accept the answer. – David Deprost Dec 16 '18 at 00:21
  • You're very welcome - glad it's working for ya now. Edit approved, and thanks for accepting my answer – eagles1283 Dec 16 '18 at 01:59
1

If you're using react application you can create index.css file and set your wanted properties for the body. Then you must import the index.css file in your index.js file and the changes will take place.

codeKid
  • 75
  • 2
  • 12
  • So there is no CSS-in-JS specific way to do this? Styling the body requires a separate css/scss file regardless? Seems kinda wasteful to create a separate file just for the body ... – David Deprost Dec 15 '18 at 17:26
  • What is the solution .. if you want to add style to body according to particular theme which you only know in js ? – RishabhRathod Sep 09 '20 at 07:19
0

As per the question if the task is as small as changing body's background color in js then below approach can also be followed any where in your code most probably in App.js

if(theme==='dark') 
 document.body.style.background = '#000'
else 
 document.body.style.background = '#FFF' 

No need to use a whole styling library for it.

Also i tried editing document.body.style, you can try that too according to below example

if(theme==='dark') 
 bgColor = '#000'
else 
 bgColor = '#FFF'

document.body.style= `background: ${bgColor}`

Remember following 2nd approach you may overwrite whole body style so please take care of that.

I hope this helps :)

RishabhRathod
  • 313
  • 1
  • 7