React: cannot read document.body.style.marginRight - css

I am having trouble reading the margin-right css property of the body. It seems to fail on initial render, but a few times it seemed to work when I was manually setting the margin-right. I expect it has something to do when when the component is rendering. Tried in useEffect and useLayoutEffect without success.
Pertinent CSS:
body {
margin-right: 10px;
}
Simple create-react-app:
function App() {
const [marginRight, setmarginRight] = useState(
document.body.style.marginRight
);
return (
<div className="App">
<p>BODY Right margin is: {marginRight}</p>
</div>
);
}

HTMLelement.style only returns inline styles. To access style from your css file, you should use:
window.getComputedStyle(document.body).marginRight

Related

Importing React State into CSS file

I am currently working on a NextJS based project, in which I need to use React State to determine the width of a div. Currently this is being calculated inside a .tsx file using consts and incremented when a button is clicked. The resultant width is then passed down as a prop to the component.
Right now, I'm using inline styling to set the width of the div, but I wanted to know if it was possible to pass the prop directly into the .module.css file I'm using as it will be tidier and much easier for media queries later on. Is that possible?
Also, is it possible to import variables from the media queries back into the .tsx file?
Main file:
const [width, setWidth] = React.useState(0)
const increment: number = maxWidthTop / totalRounds
export default function Labeller() {
function clicked() {
setWidth(width + increment)
}
return (
<Progress
width={width} />
)}
Component file:
import styles from '../../styles/Progress.module.css'
type ProgressProps = {
width: number;
}
export default function ProgressBar(props: ProgressProps) {
return (
<div className={styles.main}>
<div className={styles.bar}>
<div className={styles.base}></div>
<div style={{width: `${props.width}em`}} className={styles.top}></div>
</div>
</div>
)
}
You can't modify the css module dynamically at runtime as the css files are downloaded and parsed by the browser separately from the js. Supplying your width value using inline is styles a good way to go but you are right that it doesn't make media queries easy.
One alternative option would be to write a function that formats a css string with your width variable, and renders the output inside a style element:
import "./styles.css";
const divWidthStyles = (width: number) => `
.${styles.top} {
width: ${width}px;
}
#media only screen and (min-width: 600px) {
.${styles.top} {
width: ${2 * width}px;
}
}
`;
...
export default function ProgressBar(props: ProgressProps) {
return (
<div className={styles.main}>
/* Use style element */
<style>{divWidthStyles(props.width)}</style>
<div className={styles.bar}>
<div className={styles.base}></div>
<div className={styles.top}></div>
</div>
</div>
);
}
Another option would be to set a css variable using javascript, whenever width changes, by making use of useEffect(). Like so:
function ProgressBar(props: ProgressProps) {
const { width } = props;
const divRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (divRef.current) {
divRef.current.style.setProperty("--width", `${width}px`);
}
}, [width]);
return (
...
<div
className={"dynamic_width"}
ref={(ref) => (divRef.current = ref)}
></div>
...
);
}
And then making use of the variable in your css.module file like this:
.dynamic_width {
height: 200px;
background: red;
width: var(--width);
}
#media only screen and (min-width: 600px) {
.dynamic_width {
width: calc(2 * var(--width));
}
}
Side note; there's a library called styled-components that allows you to supply values to the styles of components easily. I find it helps to keep things very tidy and could be a more elegant solution to your problem.

Styling from separate CSS files not applied with new components

I have been trying to build a small project with React for the past few days and all went great until today. For some reason, no CSS is applied to new components! All the CSS that worked before is still up and running but if I'd add something like a div in between an already existing div, the new div will not pick up any CSS!
Example:
<div className="DivStyle"> // Styling applied!
<div className="DivStyle"> </div> // Styling completely ignored!
<div>
It is probably worth mentioning that I am still able to style the components inline.
Also, looking at the sources in Chrome, the styles are uploaded!
Here is my concrete example:
import '../styles/drawers.css';
class BottomFilterDrawer extends React.Component<IBottomFilterDrawerProps, IBottomFilterDrawerState> {
...
public render() {
return(
<Drawer
open={this.state.isOpen}
anchor="bottom"
// tslint:disable-next-line jsx-no-lambda
onClose={() => this.toggleDrawer(false)}>
<div className="BottomDrawerContainer" style={{margin: "10px"}}> // Styling for "BottomDrawerContainer" class not applied!
...
</div>
</Drawer>
);
}
}
The CSS file:
#BottomDrawerContainer {
margin: 10px;
}
I am certain that the import path is correct, Typescript wouldn't even let me run it if it weren't.
You are applying css for class not for id. So your css must be like below.
.BottomDrawerContainer {
margin: 10px;
}
if you want to apply for inner div.
.DivStyle .DivStyle {
//style for inner div
}
do not use again same id, React create error and if show any error first you solve error otherwise browser not show anything

How to limit style to component level in React?

My app tries to show emails. Sometimes the style in the email will affect the app itself.
Right now I am using the package juice to inline style in the email html. However, sometimes it cannot inline correctly. So I try to find other solutions.
I know Angular automatically add some random string in each class to make sure style in one component won't affect other component, is there a same way to do it in React? Or is there other way to limit style to the component level without using iframe? Thanks
The demo shows the p { color: red; } from the email also affects the app itself. In this case, it affects Content in app.
Live demo
class Mail extends Component {
render() {
// the style inside is from mail, in real case, it can have tens or even hundreds of different styles
const mailFromServer = `
<html>
<head>
<style>
p { color: red; }
</style>
</head>
<body>
<p>Content in mail</p>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mailFromServer}} />
</div>
);
}
}
class App extends Component {
render() {
return (
<div>
<Mail />
<p>Content in app</p>
</div>
);
}
}
There are few ways to do this.One of the way would be by passing style to the elements and defining styles as objects. For example
const styles = {
content: {
color: '#000',
backgroundColor: '#fafafa',
},
};
class Mail extends React.Component {
render() {
return() {
<p style={{styles.content}}> Content </p>
}
}
}
If you really want something scalable then you can use styled-components which for me personally work really nicely and fulfills all your styling needs.
You'll need to use a class to limit the style to a specific component's features:
import React, { Component } from 'react';
import { render } from 'react-dom';
class Mail extends Component {
render() {
const mail = `
<html>
<head>
<style>
.mail-header { color: red; }
</style>
</head>
<body>
<h1 class="mail-header">Heading in mail</h1>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mail}} />
</div>
);
}
}
export default Mail;
Styles in <style>..</style> or from CSS sheet is global. They are applied across your app.
If you have control over how the email is formatted, I would recommend setting different class names for different email types.
If you have a limited set of email types, you can specify the styles for each of them in a css sheet, and import it on your html file or Webpack.
styles.css
.important-email { color: red; }
.not-important-email { color: blue; }
// ...
// styles for different email types
Mail.jsx
class Mail extends Component {
render() {
const mail = `
<html>
<head>
</head>
<body>
<h1 class="important-email">Heading in mail</h1>
</body>
</html>
`;
return (
<div>
<div dangerouslySetInnerHTML={{__html: mail}} />
</div>
);
}
}
export default Mail;
Yes, you can use CSS Modules, which is one or more css files (written in js) in which all class names are auto-scoped locally to each component by default.
There is a good article about this here https://medium.com/#pioul/modular-css-with-react-61638ae9ea3e
You can also try to reset those known html entities which are commonly over-ridden by your Mail html. You may have to play around a bit, but, given your example, you could do something like the following:
https://stackblitz.com/edit/react-neymbb
Basically, in my sandbox I reset your paragraph color and padding to their defaults, as well as, used it in conjunction with another inline style. Depending on the entire construct of css inheritance in your app, your results may vary, but you should be able to get something workable.
More information on the css values I recommend found here:
https://developer.mozilla.org/en-US/docs/Web/CSS/initial

How to make a block appear in reactjs?

Hi and thanks for the great work here. I'm pretty new in reactjs and I'm struggling to make it work with sandbox like jsfiddle.
I have a div called "app-content" tht is supposed to appear in the middle of the document just like the following :
For some reasons , I cant make the following thing on my sandbox , and I get the following : https://jsfiddle.net/w7sf1er6/8/
JS here
export default class App extends React.Component {
render() {
return (
<div className="app-content">
</div>
);
}
};
ReactDOM.render (
<App />,
document.getElementById('root')
);
and CSS here
html {
background-color: #e3e3e3;
font-family: regular, arial, sans-serif; }
body {
margin: 0 !important;
padding: 0 !important; }
a {
text-decoration: none; }
.app-content {
width: 1200px;
height: 500px;
margin-left: auto;
margin-right: auto;
background-color: white; }
What am I mising ? I need to make it work on JSfiddle so I can share it with others developers. I wuld appreciate some help from our community.
Thanks.
You must install react-blocks via npm first if you haven't already.
Like so, npm install react-blocks
Once you have done this, you will need to import/require react-blocks within your react code.
// using an ES6 transpiler
import Block from 'react-blocks';
// not using an ES6 transpiler
var Block = require('react-blocks');
Next, the layout:
// Normal Flex layout
const App = () => {
return (
<Block layout>
<div>Alpha</div>
<div>Beta</div>
</Block>
);
};
// Reverse Flex layout
const Reverse = () => {
let { reverse } = styles;
return (
<Block style={reverse.block} layout vertical reverse>
<div>Alpha</div>
<div flex>Beta</div>
</Block>
);
};
Feel free to read more on the process here.
Hope this helps!
Your React component is not rendering to the div. You can see errors in the console log and doing "view frame source" on the HTML output pane will show you that the "div" element hasn't been replaced.
As Chris suggested, just start from a JSFiddle example that sets up React correctly.
The example above mainly differs from your code in that it imports React definitions.
<script src="https://facebook.github.io/react/js/jsfiddle-integration-babel.js" />

Component is briefly rendering without styles on first render

When I open my react app, the component below flashes with width:100%, probably because it inherits it from the material-ui card.
In my react app there are a lot of these components being rendered, each with their own width which are based on the parent component's data. I set the width with an inline style based on the props.
As I understand, the component has the inline style as it is created and there should be no delay to apply it. However I see all the SceneThumb components with 100% width for a a fraction of a second, before they apply the given inline style.
If I change the css of scene-thumb-parent to include some width, say 10% for example, then I'll see them all with 10% for a fraction of a second, before the inline style is applied. That makes me think there is a delay in applying inline css, but it really puzzles me..
Is this to be expected of react? Or of html in general? Is there any way to reduce this inline style application delay? Maybe it's something to do with the dev hot reloading setup I get from create-react-app?
SceneThumb.js (code that is irrelevant to the question has been omitted):
import React, { Component } from 'react';
import './scene-thumb.css';
import Card from 'material-ui/Card';
class SceneThumb extends Component {
render() {
return (
<div
className='scene-thumb-parent'
style={{width:this.props.width, left:this.props.left}}
>
<Card
className={this.props.selected?'scene-thumb-selected':'scene-thumb'}
>
<span>
Hello world!
</span>
</Card>
</div>
);
}
}
export default SceneThumb;
scene-thumb.css:
.scene-thumb-parent {
position:relative;
text-overflow:clip;
white-space:nowrap;
overflow:hidden;
min-width: 12px;
}
.scene-thumb-selected {
border: 2px solid red;
border-radius: 5px;
}
.scene-thumb,.scene-thumb-selected {
padding: 2px;
margin:2px;
position:relative;
}
The width prop is initially null or some other value. A moment later, the prop is updated which triggers another render. This is why you're seeing the flash you're talking about.
You can test this by adding the following to your render() function:
console.log(this.props.width)
You'll probably see it logging at least twice with different values.
There are many ways you can fix this. What makes most sense would depend on the rest of the application, and your personal preference. Regardless, here's one way:
render() {
if(!this.props.width) return null; //if it's null, render nothing.
return (
<div className='scene-thumb-parent' style={{width:this.props.width, left:this.props.left}}>
<Card className={this.props.selected?'scene-thumb-selected':'scene-thumb'}>
<span>Hello world!</span>
</Card>
</div>
);
}

Resources