How to add Sass variable to Styled components in react js - reactjs

I need to add sass variable to styled components in react js ,I have go through this link Sass-extract-js and i have followed their procedure.
but i'm stuck in this line
import styled from 'styled-components';
const Button = styled.button`
background-color: ${p => p.theme.primary} //explain this line
`;
I have created var.scss file and contains
$black:#000000;
$white:#ffffff;
$red:#f64406;
$gray:#333333;
$green:#3bbd47;
In my render
<div>
<div>
<h2>Welcome Back!</h2>
<h3>Login Your Account</h3>
</div>
Styled component
const Content = styled.div`
h1:${}//how i can get variable here
`;

This can be achieved by using theming in the styled-components. You can add variables to ThemeProvider as follows:
const theme = {
black:#000000,
white:#ffffff
red:#f64406
gray:#333333,
green:#3bbd47
}
<ThemeProvider theme={theme} >
<App />
</ThemeProvider>
and then this object can be used in the styled-components
const BlackDiv = styled`
color: ${(props) => props.theme.black}`;
For more info please check theming

Related

styled components - overwrite default headings

How can I overwrite default headings globally with styled components theme?
For colors I'm doing:
import React from "react";
import { ThemeProvider } from "styled-components";
const theme = {
colors: {
main: "#8563FF",
mainLight: "#AB93FF",
.....
}
};
const Theme = ({ children }) => (
<ThemeProvider theme={theme}>{children}</ThemeProvider>
);
export default Theme;
and them in my component I'm getting those colors trough props
${props => props.theme.colors.main}
I would like to overwrite default headings eg. h1 with my custom fontSize, weight..., so that when I'm using it in my component it looks like this:
const StyledH1 = styled.h1`
/* additional local styling for overwritten h1 */
color: ${props => props.theme.colors.main};
marginTop: 20px;
`;
On top of that, it should contains media query inside overwritten heading.
How to add overwrites to theme?
You should use createGlobalStyle and ensure that its ThemeProvider's child.
A helper function to generate a special StyledComponent that handles global styles.
const GlobalStyle = createGlobalStyle`
h1 {
color: ${props => props.theme.colors.main};
margin-top: 20px;
}
`
// will have margin-top
styled.h1``
<ThemeProvider>
<GlobalStyles />
</ThemeProvider>
You can create reset styles with createGlobalStyle and put it in the root of your project.
For example here are reset styles for all HTML attributes, you can import it in the root index file, and in the project, all default styles of HTML tags will be reset. (styles like margins of <p> or <h1> and so on)
You can do some modifies to set default values of some attributes, for example like the default color of <p>, <h1> or others
Examples of reset.css
https://gist.github.com/DavidWells/18e73022e723037a50d6
https://cssreset.com/scripts/eric-meyer-reset-css/

Overwrite styles of a component inside another in react

I have a component with its own styles:
import styles from './componentA.module.scss';
componentA.module.scss:
.A { color: green;
background: white;
font-size: 1rem;}
ComponentA.js
....
return(
<div className={styles.A}>{props.children}</div>
)
I have a ComponentB.js. In this component B I need the component A, but I need to overwrite the style color.
ComponentB.js
...
import ComponentA from './../componentA';
import styles from 'componentB.module.scss';
...
return(
<ComponentA />
)
but I want in the component B overwrite the color to the class .A. I tried in componentB.module.scss to do it and it doesn't change.
componentB.module.scss
.A {
color: red !important;
}
and it doesn't work I want to be able to overwrite the styles depending on the component that is wrapped. How can I do it? Thanks.
You have to pass Component A styles by the props and then apply to the wrapper div
const ComponentA = (props) => {
return(
<div className={styles.A} styles={props.cssStyles}>{props.children}</div>
)
}
And then
import ComponentA from './../componentA';
import styles from 'componentB.module.scss';
...
return(
<ComponentA cssStyles={{color: "red"}} />
)
You can also pass classnames as props and then merge default classnames and props classnames by this package https://www.npmjs.com/package/classnames

why styled component styling not adding

i was scratching my head from the last 2 hours that why this 3 rd party styled component is not adding i it .have a look
import React from 'react';
import styled from 'styled-components'
const StyleDiv =styled.div`
#media(max-width:600px){
body{
background-color: red;
}
}`
const Person= (props)=>{
return <StyleDiv>
<h1 onClick={props.click}>i am {props.name} and {props.age} years old as you know me as {props.children} </h1>
<input type="text" onChange={props.changed} />
</StyleDiv>
}
export default Person;
If you put selectors within the template string without the ampersand, they will refer to children of the component. https://styled-components.com/docs/basics#pseudoelements-pseudoselectors-and-nesting
Basically you can't select body within your div and you probably shouldn't.
you cannot apply global styles like this to a component, for applying global styles (i.e. styles to body, html etc.) styled-components gives a createGlobalStyles utility, it can be used like this:
import { createGlobalStyles } from 'styled-components';
const GlobalStyles = createGlobalStyle`
#media (max-width: 600px) {
body {
background-color: red;
}
}
`;
// Render GlobalStyles to the root lvvel of your app
ReactDOM.render(
<>
<GlobalStyles />
<App />
</>,
document.getElementById('root');
);
Hope it helps :)

Passing custom props to each styled component through Provider

I would like to pass a custom prop (exactly: theme name as string) to each passed styled component through Provider, so it was available throughout the css definition.
ThemeProvider almost does it, but it expects object, not the string. I do not want to pass whole object with theme settings, just the name of my theme.
I do not want to use special theme prop or similar, because then I would have to it manually every single time I create new styled component. Provider seems like the best option if only it cooperated with string.
Is there any possibility to pass a string through Provider to Consumer builded in styled components?
EDIT:
[PARTIAL SOLUTION]
I found what I was looking for when I realized styled-components exports their inner context. That was it. Having access to pure react context gives you original Provider, without any 'only objects' restriction ('only objects' is a styled-components custom provider restriction).
Now I can push to each styled component exactly what I want and if I want.
import styled, { ThemeContext } from 'styled-components';
const StyledComponent = styled.div`
color: ${props => props.theme == 'dark' ? 'white' : 'black'};
`;
const Component = props => {
const theme = 'dark';
return (
<ThemeContext.Provider value={theme}>
<NextLevelComponent>
<StyledComponent />
</NextLevelComponent>
</ThemeContext.Provider>
);
};
Hope I have this correct, from what I've been able to glean. I haven't tried this out but it seems it might work for you. This is lifted directly from the reactjs.org docs regarding context. It passed the string name of the theme down.
const ThemeContext = React.createContext('green');
class App extends React.Component {
render() {
return (
<ThemeContext.Provider value="blue">
<SomeComponent />
</ThemeContext.Provider>
);
}
}
function SomeComponent(props) {
return (
<div>
<OtherComponent />
</div>
);
}
class OtherComponent extends React.Component {
static contextType = ThemeContext;
render() {
return <ThirdComponent theme={this.context} />
}
}
I hope this helps you understand the idea behind ThemeContext from styled-components. I've passed string "blue" to ThemeContext just to show, that it should not be object and you can use just string.
import React, { useContext } from "react";
import ReactDOM from "react-dom";
import styled, { ThemeContext } from "styled-components";
// Define styled button
const Button = styled.button`
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border-radius: 3px;
color: ${props => props.theme};
border: 2px solid ${props => props.theme};
`;
// Define the name of the theme / color (string)
const themeName = "blue";
const ThemedButton = () => {
// Get the name from context
const themeName = useContext(ThemeContext);
return <Button theme={themeName}>Themed color: {themeName}</Button>;
};
function App() {
return (
<div className="App">
<ThemeContext.Provider value={themeName}>
<ThemedButton />
</ThemeContext.Provider>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Demo: https://codesandbox.io/s/styled-components-example-with-themecontext-cso55

How do i use styled components with dynamic imports

I am trying to find a way to dynamically import an svg Icon that inherits some standard styling. I havn't see anyone else writing about this... so i think i am on the wrong track.
I have tried creating an SVG wrapper in styled components but that gives me a nest of svg > svg > path
I'm not sure if this is the right idea.
I want to stay away from using inline styles in case of specificity issues later.
The SVG Icon code <-- using Create React App i am exporting the svg as a default react component
export { ReactComponent as default } from './logo.svg';
My Icon code <-- the styled.svg is something i would like to merge with the DynamicIcon... is there a way to do something like DynamicIcon as TestStyle? <-- in the documentation the as is used to change the tag type so i don't think this is right?
const TestStyle = styled.svg`
height: 1rem;
width: 1rem;
display: inline-block;
`
const Icon: React.FC<IconProps> = ({ name }: IconProps): React.ReactElement => {
const DynamicIcon = lazy((): Promise<any> => import(`../../assets/icons/${name}.tsx`));
return (
<Suspense fallback={<div>Loading ...</div>}>
<DynamicIcon />
</Suspense>
);
};
The import is working and displaying but i would like to have the component as a styled component, this will give me access to themeing and dynamically changing the SVG style with props.
ℹ - My TypeScript foo is weak so will be using vanilla JS below
You can simply wrap the dynamically loaded component with styled(DynamicIcon).
Reference: Extending Styles documentation
// Instead of 👇
// const TestStyle = styled.svg`
// height: ${props => props.size};
// width: ${props => props.size};
// display: inline-block;
// `;
const Icon = ({ name, iconSize }) => {
const DynamicIcon = lazy(() => import(`./icons/${name}.jsx`));
// ... 👇 Wrap the dynamically loaded component in `styled()`.
const StyledIcon = styled(DynamicIcon)`
height: ${props => props.size}px;
width: ${props => props.size}px;
display: inline-block;
`;
return (
<Suspense fallback={<div>Loading ...</div>}>
<StyledIcon size={iconSize} />
</Suspense>
);
};
⚠ 🔥
But be aware that the above usage of using prop.size is not a good idea as it creates a multiple classes per each width/height.
(I was trying to get around it with .attrs but couldn't get it working but I find it outside the scope of this question and leave that to you 😉)
Check out the forked demo here.
And here is how the logo looks wrapped in styled component

Resources