Styled components vs props.children - reactjs

I have been working with react using css modules till now. I wanted to switch to styled components and there is one thing that confuses me. When working with css modules i have been creating many UI components as wrappers, passing props.children in between and then styling the wrapper in specific ".module.css" file. Now when i saw how styled components work, its like creating a component and styling that one element or even styling nested jsx tags. So styled components have wrapper behaviour. Does it kinda replace usage of props.children?

No, Styled Components do not force you not to use props.children.
You can use a Styled Component as a wrapper and style children inside of it as you would do with a Component styled with a css.module:
I guess you are composing your React components like this:
// css.module
// styles.module.css
.container {
background-color: red;
}
.container > h2 {
color: green;
}
// Your React Component Wrapper:
const Wrapper = ({children}) => <div className={styles.container}>{children}</div>
// And you use it like this:
<Wrapper><h2>This text is green on a red background</h2></Wrapper>
You can do the same thing with Styled Components:
const Wrapper = ({ children }) => <StyledWrapper>{children}</StyledWrapper>;
const StyledWrapper = styled.div`
background-color: red;
& > h2 {
color: green;
}
`;
// And you use it like this:
<Wrapper><h2>This text is green on a red background</h2></Wrapper>
The result is the same and even the usage is the same, styled-components do not force you to use a certain React Composition Pattern, it's up to you whether to style container and then select children inside of it, or if to individually style all the children.
They just give you some super-powers, for example you can target a Styled Component Child inside a Styled Component Parent, by simply calling the Component name, or you have the chance to use JS variables more easily into your css code, since all props passed to a Styled Component can be retrieved by the css.
DEMO

Related

How to focus trap with styled-components? How to access classname from styled-components?

I'm currently using styled-components 5.0.1 with React. https://styled-components.com/
For context, my goal is to focus trap within a modal.
My problem is that classnames are randomly generated from styled-components so I'm not able to access these DOM nodes with querySelector. My other problem is that I'm not able to use React ref forwarding since I would have to do a lot of ref forwarding between component trees.
Is there a way to access the classname that is generated from styled-components? If so, I can use querySelector and go about the usual way of focus trapping by accessing the DOM nodes through querySelector.
Firstly, your component should be able to process the passed-in css:
import styled from "styled-components";
const Box = styled.div`
color: red;
${props => props.addCSS}
`;
const DatePicker = () => <Box>DatePicker</Box>;
Secondly, declare the css style.
import { css } from "styled-components";
const myCSS = css`
font-size: 60px;
`;
Lastly, pass it down to the child component.
<DatePicker addCSS={myCSS} />
I was able to solve this issue by accessing the DOM nodes with using a data- attribute.
For example,
const myComponent = styled.div`
// ...styles here
`;
const foo = () => (
<myComponent
data-foo-bar="foobar"
/>
);
console.log(document.querySelector('[data-a11y-id="HeaderNavBar-SearchButton"]');
// returns the DOM element for myComponent

Should i use normal tag when i am using style component?

As I mentioned in the title, Do I should use a normal tag html when i am using Style Component?
For example:
My div is styled in Styled Component and if I have a p tag inside it, should i styled this p tag as well?
or i can just have a normal tag and 'style component tag'
I sometimes mix both. For example,
import React from 'react';
import styled from 'styled-components';
const Box = styled.div `
background-color: black;
padding: 2rem;
h3 {
color: orange;
}
p {
color: white;
}
`
export const InfoBox = () => {
return (
<Box>
<h3>Information</h3>
<p>An example of paragraph text</p>
</Box>
);
};
In this example <h3> and <p> are both normal html tags, whilst <Box> is a styled component. And as you can also see in this example, the <h3> and <p> tags can still be styled with css (as long as they are children of <Box>).
With styled-components you are basically styling only a single html element or react component at a time.
const StyledDiv = styled.div``;
const StyledMyComponent = styled(MyComponent)``;
This creates and returns a react component. Every react component has an implicit children prop, so you use your StyledDiv to wrap any other element in JSX, it doesn't really matter much.
<StyledDiv>
<p>This is my p-tag text wrapped in my styled div-tag</p>
<StyledP>This is my styled p-tag text wrapped in my styled div-tag</StyledP>
</StyledDiv>
You only need style a <p> if you need it to be styled, otherwise it doesn't matter since the child element/component can be any valid JSX element.

Add style.css for a specific component in react

I'm trying to add a CSS file for a specific component in react, but the CSS file apply in all component
How can I add style.css for a specific component?
import React, { Component } from "react";
import { Link } from "gatsby";
import Layout from "../components/layout"
import Footer from "../components/Globals/Footer"
import "./crm2.css"
class Crm extends Component {
render() {
...
}
}
You can refer to this link on which the narrator is explaining the options you have for styling the React Components. Styling in React
Your options are
In-Line styling
Using variables
styling by means of a function or method inside the component
Once you take a look at the video link, you will know what approach suits you the best.
Your CSS className must be unique. If you write CSS for this class then it will be applied to the specified component.
There are two components in React
Built-in component (like <p>, <div>, <span>, etc)
React component (like <App/>,<Product>, etc)
React components allows you to break up the UI into different pieces so that it can then be reused and handled individually. It is the Dot-notation component like <UserContext.Provider> and any component which starts with a capital letter.
These components can be styled if you provide a unique className to those components and you write a CSS style for that.
You might have styled the built-in component as shown below
style.css file:
p {
font-size:14px;
color: red;
}
Using the above approach, the CSS would be applied to all the <p> component in all the JSX file.
If you have wanted to style the React component then you need to select those components and styled it as shown below.
<Product className = "items" />
CSS would be
.items {
color: red;
...
}

Material-UI #next Does not support props-based styling?

With the arrival of Material-UI#next comes the replacement of LESS-based styling with CSS-to-JS-based styling. However, the component demos on Material-UI's website appear to ignore the creation of props-based-styling. I'm trying to create divs containing various Material-UI components at specific absolute heights on my page, however, the requirement of the stylesheet being predefined outside of the class means that the properties within the stylesheet can't be based on props passed to the component. Am I missing something?
For example:
import React, {Component} from 'react';
import {withStyles, createStyleSheet} from 'material-ui/styles';
import Button from 'material-ui/Button';
const styleSheet = createStyleSheet({
container: {
position: "absolute",
top: /*How can this be dependent upon the props passed to the component?*/,
height: /*How can this be dependent upon the props passed to the component?*/,
}
});
class Foo extends Component {
render() {
let classes = this.props.classes;
return (
<div className={classes.container}>
<Button raised/>
</div>
);
}
}
export default withStyles(styleSheet)(Foo);
The example component displayed above can't have props-dependent styles, because props is not defined when the stylesheet is created. So how do I solve this problem? IS there a solution?
I would strongly advise you check out Styled Compoments. They make styling very simple and even allow you to pass third party components (in your case Material UI components). They also allow you to pass in props like the following:
const Stylesheet = styled.div`
color: ${props => props.primary ? 'white' :
`
<Stylesheet primary>My Div</Stylesheet>
Check out the docs for more details, that was a very simple example, but they are super easy to work with and you can accomplish exactly what you need with them.

Target specific CSS classes with Styled Components

How would I go about styling something like the react-datepicker with styled-components? The datepicker library looks like it uses some type of BEM style (screenshot below) which I would normally just use their provided class names and style those using Sass. But, how would I target those class names with styled-components? Is that even possible?
Since styled-components is just CSS™ you'd do it like with any other style sheet, by using the class names react-datepicker provided.
The only difference is that you'll have to wrap the datepicker in one wrapper styled component which applies all of these classes:
const Wrapper = styled.div`
&.react-datepicker {
color: blue;
}
`
<Wrapper>
<Datepicker />
</Wrapper>
Searching for hours, I found that the best solution is to add a stylized parent component (it can be a div) overlying the component that needs a className and add the definition of the className directly into the stylized parent component.
VERY IMPORTANT:
A space is needed between the ampersand & and the class for this to take effect!
const StyledParent = styled.div`
& .your-class-name {
border-color: red;
}
`;
<StyledParent>
<Datepicker yourClassName="your-class-name" />
</StyledParent>
If you ever need to access and style another component you can do this if they are not in the same file:
Export whatever you need to access:
export { Wrapper as CircledButtonWrapper };
Import it where you need it:
import { CircledButtonWrapper } from "/Bla/CircledButton";
Use it where you need to style it:
const Wrapper = styled.div`
/* Some other styles */
&:hover {
${CircledButtonWrapper} {
opacity: 1;
}
} `;
Edit:
I see now that the question was refering to accessing className...

Resources