How to use StyledComponents theme inside of Component - javascript

Below I've created a style called Link. However the theme is inside of this.props. What is the way to get the theme out of props and passed into the Link styled component?
ReferenceError: theme is not defined
import React from 'react';
import styled from 'styled-components';
import { withTheme } from 'styled-components';
export const Link = styled.p`
position: absolute;
z-index: 10;
bottom: 20px;
right: 300px;
width: 100%;
font-size: 1.5rem;
text-align: right;
cursor: pointer;
a {
color: ${theme.apricot}; // <-- error
cursor: pointer;
:hover {
color: ${theme.offWhite}; // <-- error
}
}
`;
class NomicsLink extends React.Component {
render() {
console.log(this.props.theme);
return (<Link>Powered by Nomics APIs.</Link>)
}
}
export default withTheme(NomicsLink);
This console.log prints the following:
{ red: '#FF0000',
black: '#393939',
grey: '#3A3A3A',
lightgrey: '#E1E1E1',
offWhite: '#EDEDED',
apricot: '#FEBE7E',
margin: 0,
padding: 0 }

All styled-components receive theme prop automatically.
You can access them inside the styled component with:
const Link = styled.a`
color: ${props=>props.theme.apricot};
`;
More options on theming, see docs

Related

How can I use dynamic css variables in react?

Trying to do a drop-shadow hover effect in react. I thought I'd use inline style attribute so each icon can have a different color when it's hovered over. I'm stuck on how to achieve this. In my IconGrid component I've created an array of objects, each has an image and the image color respectively. Then I map through it and return the individual GridItem component, but I'm stuck as to how I can use the unique color property for the css drop-shadow effect. I'm getting the red lines in my GridItem component because it's clearly not the written correctly. How can I achieve this?
IconGrid Component
import React from "react";
import "./index.scss";
import GridItem from "./GridItem";
import XD from "../../../assets/images/adobe-xd.png";
import PS from "../../../assets/images/adobe-photoshop.png";
import AI from "../../../assets/images/adobe-illustrator.png";
import CSS from "../../../assets/images/css.png";
import GSAP from "../../../assets/images/gsap.png";
import GULP from "../../../assets/images/gulp.png";
import HTML from "../../../assets/images/html.png";
import JS from "../../../assets/images/javascript.png";
import NODE from "../../../assets/images/nodejs.png";
import REACT from "../../../assets/images/react.png";
import WP from "../../../assets/images/wordpress.png";
import PHP from "../../../assets/images/php.png";
const IconGrid = () => {
const icons = [
{ img: XD, color: "#2E001E" },
{ img: PS, color: "#31C5F0" },
{ img: AI, color: "#FF7F18" },
{ img: HTML, color: "#E44D26" },
{ img: CSS, color: "#264DE4" },
{ img: WP, color: "#01579B" },
{ img: PHP, color: "#6181B6" },
{ img: JS, color: "#F7DF1E" },
{ img: GSAP, color: "#8AC640" },
{ img: GULP, color: "#D34A47" },
{ img: NODE, color: "#83CD29" },
{ img: REACT, color: "#61DBFB" },
];
return (
<>
<div className="flex-grid">
{icons.map((icon, idX) => (
<GridItem key={idX} icon={icon} />
))}
</div>
</>
);
};
GridItem Component
import React from "react";
import "./index.scss"
const GridItem = ({ icon }) => {
return (
<div style={{`--color: ${icon.color}`}} className="flex-item">
<img src={icon.img} alt="" />
</div>
);
};
export default GridItem;
And the CSS
.flex-item {
flex-basis: 22.5%;
padding: 2.5rem 0;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.4s ease-in-out;
position: relative;
&:hover {
transition: all 0.4s ease-in-out;
filter: drop-shadow(0 0 20px var(--color)) drop-shadow(0 0 40px var(--color))
drop-shadow(0 0 60px var(--color));
}
img {
max-width: 80px;
height: auto;
}
}
I think you should set your inline style as below, keeping the key: value form.
import React from "react";
import "./index.scss"
const GridItem = ({ icon }) => {
return (
<div style={{'--color': `${icon.color}`}} className="flex-item">
<img src={icon.img} alt="" />
</div>
);
};
export default GridItem;

React color background on event

I use the npm package use-dark-mode as the name implies, it makes it possible to change the theme to light or dark, The problem is that I want to change the background-color of some blocks when changing the theme to dark, and vice versa, return the old color when I switch to light mode, for example, my block background is orange, I switch to dark mode, it turns red and when I switch to light mode, it returns old orange
App.js
import React from 'react';
import './App.css'
import Content from "./components/Content/Content";
import Dark_Mode from "./components/Dark Mode/Dark_Mode";
const App = () => {
return(
<div>
<Dark_Mode />
<Content />
</div>
);
};
export default App;
Content.jsx
import React from 'react';
import './style.css'
const Content = () => {
return (
<>
<div className={"content_container"}>
<h3>Hello from React.JS</h3>
</div>
</>
);
};
export default Content;
Dark_Mode.jsx
import React from 'react';
import useDarkMode from 'use-dark-mode';
const DarkModeToggle = () => {
const darkMode = useDarkMode(false);
return (
<div>
<button type="button" onClick={darkMode.disable}>
☀
</button>
<button type="button" onClick={darkMode.enable}>
☾
</button>
</div>
);
};
export default DarkModeToggle;
style.css
#import '../../App.css';
.content_container {
margin: auto;
width: 500px;
max-width: 100%;
background: orange;
}
.content_container h3 {
text-align: center;
}
App.css
body.light-mode {
background-color: #fff;
color: #333;
transition: background-color 0.3s ease;
}
body.dark-mode {
background-color: #1a1919;
color: #999;
}
:root {
--color-orange: orange;
}
As you can see, I have App.css when the theme changes, it changes the background of the <body>, I still have Content.jsx when switching theme I want to change the background of the block with the className content_container which is connected to style.css, In addition, you may have noticed that I tried to use global styles, but I failed. Finally, I would like to show a screenshot on the site for a clear understanding of everything.
You could give the root element a class on theme change and use css variables in root, but be class specific:
Dark_mode.jsx:
function setTheme(themeName) {
document.documentElement.classList.remove('light-theme', 'dark-theme');
document.documentElement.classList.add(themeName);
}
const DarkModeToggle = () => {
const activateDarkTheme = () => setTheme('dark-theme');
const activateLightTheme = () => setTheme('light-theme');
return (
<div>
<button type="button" onClick={activateDarkTheme}>
☀
</button>
<button type="button" onClick={activateLightTheme}>
☾
</button>
</div>
);
};
Styles:
:root, // this is used for the default theme, will be overwritten by other styles with classes because of specifity
:root.dark-theme {
--color-bg: #000;
}
:root.light-theme {
--color-bg: #fff;
}
I found a more convenient solution! although it is my fault, I was a little inattentive and did not study the documentation of this package that I use in my project, here is a simple solution
Content.jsx
import './Content.css'
import useDarkMode from 'use-dark-mode';
export default function Content () {
const { value } = useDarkMode(false);
return <div>
<div className={value ? 'Dark_Mode' : 'Light_Mode'}>
<h3>Hello from React.JS</h3>
</div>
</div>
}
Content.css
.Dark_Mode {
margin: auto;
max-width: 100%;
width: 400px;
height: 275px;
background-color: orange;
}
.Light_Mode {
margin: auto;
max-width: 100%;
width: 400px;
height: 275px;
background-color: rgb(24, 106, 199);
}

Pass background as prop in styled-components

I am trying to pass background as a prop in styled-components but I'm not sure how to pass this via my cdn function as it doesn't output correctly in the css
this is the output of the css:
background: url(https://local.dev:5601/pub/media/icons/menu/function (props) { return props.background;}.png);
How can I pass the props via my cdn function?
config.js
export function cdn(path) {
return `https://local.dev:5601/pub/media/${path}`;
}
class Config {
cdn
}
export default Config;
App.js
import React from "react";
import styled from 'styled-components'
const Circle = styled.span`
display: block;
position: relative;
width: 35px;
height: 35px;
cursor: pointer;
border-radius: 50%;
background: url("${cdn('icons/menu/' + (props => props.background) + '.png')}");
margin: 5px;
`
const CircleWrap = styled.div`
display: flex;
flex-wrap: wrap;
padding: 0 0 5px 0;
`
class App extends React.Component {
selectColor = (color) => {
this.props.selectColor(color);
}
render() {
return (
<SettingDrop
title={"Profilfarbe"}
closeDropdown={this.props.closeDropdown}
openDropdown={this.props.openDropdown}
isOpen={this.props.isOpen}
isHidden={this.props.isHidden}
isValid={this.props.isValid}
icon={<ProfilFarbe />}
>
<CircleWrap>
{console.log(this.props.colors)}
{this.props.colors.map( color =>
<Circle
background={color.hash}
onClick={()=>this.selectColor(color.alias)}
>
</Circle>
)}
</CircleWrap>
</SettingDrop>
);
}
};
the following syntax will work:
background: url("${cdn('icons/menu/')}${props => props.background}.svg");

How to style child components in react styled-components

I'm trying to style the child component of a styled-component, but it sends the css to the parent instead of the child/ This is my code,
export const Card = styled.div`
position: relative;
${props => props.horizontal && `
${CardImage}{
max-height: 60%;
overflow: hidden;
}`}
`
export const CardImage = styled.div`
position: relative;
`
EDIT: When I add a condition before rendering that's when it doesn't work
You're almost there, you're just missing a $ in your code and you'll need to move the CardImage above the Card component:
export const CardImage = styled.div`
position: relative;
`
export const Card = styled.div`
position: relative;
${CardImage}{
max-height: 60%;
overflow: hidden;
}
`
Edit (04/04/2018):
If you want to add a condition around a whole block like you have, you need to import the css function from styled components and use that:
import styled, {css} from "styled-components";
export const CardImage = styled.div`
position: relative;
`
export const Card = styled.div`
position: relative;
${props => props.horizontal && css` // - Notice the css` here.
${CardImage}{
max-height: 60%;
overflow: hidden;
}
`}
`
const StyledCard = styled.div`
//parent styles goes here
`;
const StyledImage = styled.img`
//image styles
`;
class CardImage extends Component {
render() {
return <StyledImage/>
}
export default class Card extends Component {
render() {
return <StyledCard>
<CardImage/>
</StyledCard>
}
}
Should it work for you?

How to achieve tag agnostic styled components?

If I want a button but, only the presentational part of that, so if I do:
import styled from 'styled-components'
const Button = styled.button`
color: red;
text-align: center;
`
I'm forced to render a button tag, but what about if semantically I need an anchor?
Use the "as" polymorphic prop in v4
copy/pasta from the example in the docs:
const Component = styled.div`
color: red;
`;
render(
<Component
as="button"
onClick={() => alert('It works!')}
>
Hello World!
</Component>
)
styled-components provides withComponent that'll be useful for cases where you want to use an a different tag with a component. This is similar to #siddharthkp's answer in function, but uses the API.
Example from the documentation:
const Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
// We're replacing the <button> tag with an <a> tag, but reuse all the same styles
const Link = Button.withComponent('a')
// Use .withComponent together with .extend to both change the tag and use additional styles
const TomatoLink = Link.extend`
color: tomato;
border-color: tomato;
`;
render(
<div>
<Button>Normal Button</Button>
<Link>Normal Link</Link>
<TomatoLink>Tomato Link</TomatoLink>
</div>
);
You can use it with a anchor tag as well, there's nothing stopping you.
import styled from 'styled-components'
const Button = styled.a`
color: red;
text-align: center;
`
If you want to keep both, you can reuse the styles by pulling them out:
import styled from 'styled-components'
const styles = `
color: red;
text-align: center;
`
const Button = styled.button`
${styles}
`
const LinkButton = styled.a`
${styles}
`
I've asked the same question on styled-components issue tracker: https://github.com/styled-components/styled-components/issues/494
And the current "solution" that I've found is:
// agnosticStyled.js
import React from 'react'
import styled from 'styled-components'
export default styled(
({tag = 'div', children, ...props}) =>
React.createElement(tag, props, children)
)
And then when you need it:
import React from 'react'
import styled from './agnosticStyled'
const Button = styled`
color: palevioletred;
text-transform: uppercase;
`
export default Button
And finally:
import React from 'react'
import Button from './Button'
const Component = () =>
<div>
<Button>button</Button>
<Button tag="button">button</Button>
<Button tag="a" href="https://google.com">button</Button>
</div>
export default Component
Here a full functioning example: https://codesandbox.io/s/6881pjMLQ
Since we're just using JavaScript, why not use a function?
const myButtonStyle = (styled, tag) => {
return styled[tag]`
color: red;
text-align: center;
`
}
const Button = myButtonStyle(styled, 'button')
As #typeoneerror pointed out, styled-components provides WithComponent. You can use this to to create a new component based on a prop containing the tag. Piggybacking off the example, it would look like this:
const _Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
const Button = ({ as: tag = 'button', children, ...props }) => {
// We're replacing the <button> tag with whatever tag is assigned to the 'as' prop (renamed to 'tag' and defaulted to button), but reuse all the same styles
const Composed = _Button.withComponent(tag);
// We return the newly-created component with all its props and children
return <Composed {...props}>{children}</Composed>;
};
render(
<div>
<Button>Normal Button</Button>
<Button as='a'>Normal Link</Button>
</div>
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Categories

Resources