what does this syntax in styled-components actually mean? - reactjs

I've just started using styled-components and saw that they call what i presume is a function like so:
import styled from "styled-components"
const Button = sytled.button` <--- this
// css goes here
`
I've never seem that syntax before and wanted to know if someone could point me to some docs about what it actually is.

It's called tagged template literals. The "tag" is the function before the template literal, which is called with its parameters being the template and template's variables. The parameters are as follow:
An array with all the string parts between the ${variables}.
First ${variable} of the template.
Second ${variable} of the template.
etc...
For example, I have written a function named tag that does the same as the function template literals use to process when you don't specify any tag function (a.k.a its default function):
function tag(stringParts, ...values){
return stringParts.reduce((accum, part, index) => accum + values[index-1] + part);
}
Calling it this way
tag`Hello, ${name}! I found ${count} results.`
yields the same result as
`Hello, ${name}! I found ${count} results.`
and the params fed to the tag function are ['Hello, ', '! I found ', ' results.'], name and count.

That's how you set the CSS rules for the <button> element.
So then you can use it as such:
<Button>Hello world</Button>
and all the styles you wrote above would get applied to all <Button> elements

Styled-components is a library used for styling react components.
import styled from "styled-components"
const Button = sytled.button` <--- this
// css goes here
`;
`` <-- these are template literals which was introduced in ES6.
styled is an object here and when you say styled.button it means that we are styling html tags. So you can style a div, container, h1 etc. You want to use standard css to style these html tags and styled-components create a random classname for the same.
let's say you want to style a div. You name it a Wrapper. The naming covention is first letter always capital.
const Wrapper = styled.div`
background: #c0c0aa; /* fallback for old browsers */
background: -webkit-linear-gradient(to right, #1cefff, #c0c0aa); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to right, #1cefff, #c0c0aa); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
height: 100%;
width: 100%;
`;
now you can wrap your content in render () of react.
<Wrapper>
//Your code in render of react class goes here
//thus instead of <div className = 'Wrapper'>
//you use the above code
//styled-components automatically generates random classnames solving major problems
</ Wrapper>
for more information see Max Stoiber's keynote at React Amsterdam.
https://www.styled-components.com/docs/basics#motivation

Related

import { styled } from '#mui/material/styles'; displayName not showing

Using Mui styled function to style both jsx elements and MUI components. The displayName is not showing when I debug the element in Chrome or any browser for that matter.
Anyone know how to fix this.
I'm using Vite for my setup.
const MyComponent = styled('div')`
display: flex;
`;
As you can see from the below screenshot its not showing MyComponent display name instead its showing css-1vht943
You can see class only inside the Element tab. When you click on one of the lines which contains the class name.
You can find all the CSS related to that class under the styles tab including display name for your case. Please check the image below
If you want to have a name I think you can use styled('div', { name: 'MyTheme'}), then you will see something like <div class="css-t7mscw-MyTheme-root"></div>. Don't know if this is what you want, but here it is vaguely mentioned in the doc.

Is there a way to easily add className to all tags in JSX?

I've been told that I shouldn't use HTML tags to style it in the CSS but rather use classes. Okay, not a problem I'll just add className to the tags. However there are quite a few of them in the code, so I was just wondering if there was a better way than just copy pasting the className into each tag or if there's a way to say for example all p tags should have class "text".
if all p tags should have a particular style then you should highly consider styling all the p tags directly via CSS
p {
font-size: 16px;
/* Your Styles here */
}
p.specific {
font-size: 24px;
/* Override styles for specific elements here */
}
Now answering the actual question. This can be done via JavaScript but once again I don't recommend this as this will have serious performance issues if there are a lot of nodes on the page.
document.getElementsByTagName("p").forEach(p => p.classList.add("text"));
Since you have tagged this as react, you can also extract the paragraph into its own component
const P = ({ children }) => {
return <p className="text">{children}</p>;
};
You can either add class to all elements like Mailk suggested.
document.querySelectorAll("p").forEach(p => p.classList.add("text"));
or you can simply find and replace all the p tags using the text editor.
find: <p
replace to: <p className="text"

How to test the style inside the CSS class for React component using Jest and Enzyme?

Consider in CSS,
.content
{
width:500px;
box-sizing: border-box;
}
I have added this css class inside react component as following
const Banner = () => {
return (<div className="content">This is message content</div>);
}
How to write jest and enzyme test cases to ensure the 'box-sizing' with 'border-box' applied properly?
Notes: I can write the test case to ensure the ".content" class added to this element. But exactly, i need to write test case to ensure the value in 'box-sizing'.
I am not sure how to fix your issue, but keep in mind your test will not cover
* {
box-sizing: border-box;
}
if you will defined somewhere alse.
From my perspective, it does not make sense to test styles, because we can not guaranty from the test perspective that element will look like we want to. So still you will need to open the browser and check your element works properly, but you are writing tests to avoid it.
By adding this code to Banner.test.js file, it'll check if className called content have inline style property for box-sizing and is it equal to border-box or not. But it'll test only inline styles.
const banner = shallow(<Banner/>);
it("render propperely", () => {
expect(banner).toMatchSnapshot();
expect(banner.find(".content")
.get(0).props.style).toHaveProperty("box-sizing", "border-box");
});

how to import css file in react when generating static html and inject imported css into html head tag?

I am trying to generate static html from react using renderToStaticMarkup method. The problem I am facing right now is that I am not able to import css into react component. I want to import css in my React components like css-modules (import styles from './style.css'). And then inject that loaded css into generated static html head. How can I accomplish that?
P.S. I can't use webpack due to some constraints. If there is any babel plugin availabe for this specific case, then please let me know.
Here is how I am generating static html from react component:
const reactElement = require('react').createElement;
const ReactDomServer = require('react-dom/server');
const renderHTML = Component => {
return ReactDomServer.renderToString(reactElement(Component))
}
You can pass a URL in as a prop and render a <link/> tag. Made an example here, not sure if that would meet your needs or if you need it to be a style tag.
This may be challenging without a lot of custom logic.
If you want to inline the CSS only for the initial render and then fetch the rest after the initial render, styled-components may be a better option because it supports exactly what you're trying to achieve without too much configuration: https://www.styled-components.com/docs/advanced#server-side-rendering
May be I am too late you can also create It like this way.
React.createElement("style", {},[ "body {background-color: powderblue;}
h1 {color: blue;}
p {color: red;}" ])
Output:
<style>
body {background-color: powderblue;}
h1 {color: blue;}
p {color: red;}
</style>
Since createElement take 3 params and last one is children we can put our vanila css inside it as a children. You can put any imported file in the form of string and it will convert to style tag

How to get CSS Modules to work with Reactstrap cssModule propType?

I noticed most form elements in the Reactstrap documentation have a PropType of a cssModule. I would assume that means I could override the default Reactstrap styles and do something like this:
Formtext.module.css
.formtext {
background-color: blue;
border: 2px solid black;
margin: 10px;
}
SimpleForm.jsx
import styles from "./Formtext.module.css";
...
<FormText cssModule={styles.formtext}>
This is some placeholder help text...
</FormText>
```
However, this doesn't seem to work. Checking my react dev tools the cssModule prop evaluates to undefined.
I'm using Using Reactstrap 5.0 and create-react-app 1.1.5
Is there something I'm unaware of that I need to do?
Do I need to eject to be able to use css-modules?
Can someone point me to an example of how to use the Reactstrap's cssModule prop correctly?
For reference here is the proptypes definition from Reactstrap docs
FormText.propTypes = {
children: PropTypes.node,
inline: PropTypes.bool,
tag: PropTypes.oneOfType([PropTypes.func, PropTypes.string]), // default: 'small'
color: PropTypes.string, // default: 'muted'
className: PropTypes.string,
cssModule: PropTypes.object,
};
On cssModule
It looks like cssModules doesn't behave quite like you would think; the prop doesn't take a single, overriding class - it takes a rejected class and a replacement class.
Reactstrap uses mapToCssModules to get this done. See its documentation here. Take note of the usage example:
<Example tag="div" cssModule={{ 'w-100': 'w-75' }} />
So your case would look something like this:
<FormText cssModule={{ 'form-text' : styles.formtext }} />
This will completely surpress the 'form-text' class though (which in your case, only contributes display: block. If you'd like to override more selectively, see below.
Try this instead
In the FormText source code, it looks like you may be able to do your overrides in a different way:
If you want to omit the form-text class altogether, include inline as a prop,
If you want to omit any color-related bootstrap classes, set 'color' to false (or something falsy),
set the className prop to your CSS Module object (styles.formtext).
<FormText className={styles.formText} color='' inline>
Test formtext
</FormText>
The most important part here is actually the className prop. You can also further override styling by including a tag prop (again, check the FormText docs).
Hope this was helpful! Happy holidays! 🦃🎅
I did not really get the accepted answer, but I had the same problem recently and in my opinion, cssModule behaves exactly as one would expect.
You just pass an imported module object and then specify classes they will be referenced towards the module.
Here is my example (from create-react-app) how I did fix Navbar to get it's bootstrap styles from my bootstrap module (as I don't import bootstrap globally):
import cx from 'classnames';
import bootstrap from 'bootstrap/dist/css/bootstrap.css';
import navbar from './navbar.css';
let styles = Object.assign({}, bootstrap, navbar);
public render() {
return (<Navbar cssModule={styles} className={cx(styles.navbarExpandSm, styles.navbarToggleableSm, styles.borderBottom, styles.boxShadow, styles.mb3)} light>[your menu here]</Navbar>);
}
This simply says the control to take the styles module and reference all the class names passed in classNames towards it. If you take a look at the mapToCssModules method, it is exactly what it does.
https://github.com/reactstrap/reactstrap/blob/d3cd4ea79dcaf478af5984f760ff1290406f62a5/src/utils.js#L53
In my case, it allows the control to pick up the original bootstrap styles and I can override what I need in my own module.

Resources