How to style child components in react styled-components - javascript

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?

Related

Unable to extend react component in styled-component

I am trying to extent react component in styled-component and trying to add custom style on extended component but unable to see the style changes that I am applying
I have created a button component in /src/newbutton.js with following code
import styled from "styled-components";
const Button = styled.button`
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
export const NewButton = ({ className, children }) => {
return (
<Button primary>Primary</Button>
)
}
And extending and creating another button component with custom style in /src/custom-button.js with following code
import styled from "styled-components";
import { NewButton } from './button'
const ButtonWrapper = styled(NewButton)`
width: 100%;
color: red
`;
const ExtendedButton = ({ className, children }) => {
return (
<ButtonWrapper />
)
}
I have added the custom style like width: 100% & color: red but it is not applying on ExtendedButton. Infect colour and width is same as NewButton
You need to pass a className to your NewButton in order to customize it, using styled-components.
Styled components works by creating a unique className that associated with a component and its CSS.
export const NewButton = ({ className, children }) => {
return (
<Button className={className} primary>Primary</Button>
)
}
I am posting the complete working code for future reference based on #Flat Globe solution. And it is working fine as expected.
I have modified the Button component code just by adding className in /src/newbutton.js with following code
import styled from "styled-components";
const Button = styled.button`
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
export const NewButton = ({ className, children }) => {
return (
<Button primary className={className}>Primary</Button>
)
}
I have also modified the extended-button code by just passing the className in /src/custom-button.js. check the full code below
import styled from "styled-components";
import { NewButton } from './button'
const ButtonWrapper = styled(NewButton)`
width: 100%;
color: red
`;
const ExtendedButton = ({ className, children }) => {
return (
<ButtonWrapper className="extended-button"/>
)
}

import export styled component reactjs

i want to split page between styling and app
example
in page style.js
import styled from "styled-components";
//i dont know how to export all const
export const Container = styled.div`
display: flex;
flex-direction: row;
`;
export const Sidebar = styled.div`
width: 20%;
height: 100%;
background-color: #f9f9f9;
`;
and in page app.js
import * as All from "./style.js"
//i dont know, how to import all const in style.js
function App(){
return(
<Container>
<Sidebar>
</Sidebar>
</Container>
)}
how to export and import all const when const in style.js there are so many?
another option you can export like this :
import styled from "styled-components";
const Container = styled.div`
display: flex;
flex-direction: row;
`;
const Sidebar = styled.div`
width: 20%;
height: 100%;
background-color: #f9f9f9;
`;
export {Container,Sidebar}
and you can import like this :
import { Container,Sidebar } from './style';
function App() {
return (
<Container>
<Sidebar>
</Sidebar>
</Container>
);
}
There is a beautiful way to do that. This way also let you know which component is styled-component or single component.
// style.js
export const Styled = {
Container: styled.div`
display: flex;
flex-direction: row;
`,
Sidebar: styled.div`
width: 20%;
height: 100%;
background-color: #f9f9f9;
`,
}
import { Styled } from './style';
function App() {
return (
<Styled.Container>
<Styled.Sidebar>
</Styled.Sidebar>
</Styled.Container>
);
}
Dae Hyeon Mun's approach is great, but you can simplify it further and avoid having to refactor your styles.js file by using a wildcard import, which essentially creates a module object so you don't have to!:
// style.js
export const Container = styled.div`
...
`;
export const Sidebar = styled.div`
...
`;
// app.js
import * as Styled from './style';
function App() {
return (
<Styled.Container>
<Styled.Sidebar>
</Styled.Sidebar>
</Styled.Container>
);
}
More details: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#creating_a_module_object
You can use "export const" like you already did for exporting. The simplest way to import those const is:
import * as styled from "./style.js"
//this will import all 'export const' containing 'styled' from "./style.js"
function App(){
return(
<Container>
<Sidebar>
</Sidebar>
</Container>
)}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Use Css modules add conditional transition styling to my side navigation

I would like to add some transition styling to my side navigation on my app. I am able to do this using normal classes however in this tutorial they use css modules and i am unsure how to do this using css modules.
I would like my nav to glide in and out, at the moment it jumps statically when the onClick function fires - toggleSideDrawer.
I have used this logic but I am not sure if it is doing anything:
className={props.toggleSideDrawer ? classes.SideDrawerOpen : classes.SideDrawer
Essentially i want that when the user clicks the toggle, the transform property switches from translateX(-100%) to translateX(0) but this is not happening.
Side nav code:
import React from "react";
import Logo from "../../Logo/Logo";
import NavigationItems from "../NavigationItems/NavigationItems";
import Backdrop from "../../UI/Backdrop/Backdrop";
import Aux from "../../../hoc/Aux";
import classes from "./SideDrawer.css";
const SideDrawer = props => {
return (
<Aux classname={classes.SideDrawer}>
<Backdrop
showBackdrop={props.showSideDrawer}
clicked={props.toggleSideDrawer}
/>
{props.showSideDrawer && (
<div
onClick={props.toggleSideDrawer}
className={
props.toggleSideDrawer ? classes.SideDrawerOpen : classes.SideDrawer
}
>
<div className={classes.Logo}>
<Logo />
</div>
<nav>
<NavigationItems />
</nav>
</div>
)}
</Aux>
);
};
export default SideDrawer;
Where the code is used in my Layout component:
import React, { useState } from "react";
import Aux from "../Aux";
import classes from "./Layout.css";
import Toolbar from "../../components/Navigation/Toolbar/Toolbar";
import SideDrawer from "../../components/Navigation/SideDrawer/SideDrawer";
const layout = props => {
const [showSideDrawer, setShowSideDrawer] = useState(false);
return (
<Aux>
<SideDrawer
showSideDrawer={showSideDrawer}
toggleSideDrawer={() => {
setShowSideDrawer(!showSideDrawer);
}}
/>
<Toolbar
onMenuClick={() => {
setShowSideDrawer(!showSideDrawer);
}}
/>
<main className={classes.mainContent}> {props.children} </main>
</Aux>
);
};
export default layout;
CSS:
.SideDrawer {
position: fixed;
width: 280px;
max-width: 70%;
height: 100%;
left: 0;
top: 0;
z-index: 200;
background-color: white;
padding: 32px 16px;
box-sizing: border-box;
transform: translateX(-100%);
}
#media (min-width: 500px) {
.SideDrawer {
display: none;
}
}
.Logo {
height: 11%;
text-align: center;
}
.SideDrawerOpen {
position: fixed;
width: 280px;
max-width: 70%;
height: 100%;
left: 0;
top: 0;
z-index: 200;
padding: 32px 16px;
box-sizing: border-box;
background-color: red;
transform: translateX(0);
transition: transform 0.3s ease-out;
}
The thing is that you need the element will has the transition rule all the time.
My suggestion is to set a static class which which will hold all the styles and addd another one only for overriding transform to make it move.
Something like that (it uses scss but it's easy to do it with css)
.SideDrawer {
position: fixed;
width: 280px;
max-width: 70%;
height: 100%;
left: 0;
top: 0;
z-index: 200;
background-color: white;
padding: 32px 16px;
box-sizing: border-box;
transition: transform .3s ease;
transform: translateX(-100%);
&.show {
transform: translateX(0);
}
}
export const App = () => {
const [showSideDrawer, setShowSideDrawer] = useState(false);
const sidebarClasses = classname([
styles.SideDrawer,
{
[styles.show]: showSideDrawer
}
]);
const ToggleSidebar = () => {
return (
<button onClick={() => setShowSideDrawer(!showSideDrawer)}>
Toggle Sidebar
</button>
);
};
return (
<Fragment>
<h1>App</h1>
<div className={sidebarClasses}>
<div>Sidebar content</div>
<ToggleSidebar />
</div>
<ToggleSidebar />
</Fragment>
);
};
https://codesandbox.io/s/xenodochial-framework-04sbe?file=/src/App.jsx
#MoshFeu helped me fix this.
The problem is that you render the drawer only when showSideDrawer so before it becomes true, the sidebar is not in the DOM yet so the transition is not affecting it.
The solution is to keep it in the DOM all the time but toggle . Open class to change the style.
There are libraries that knows to make the transition works even for elements that are not in the DOM but it's a bit more complicated.
code fix for SideDrawer.js without the conditional within the return
class SideDrawer extends Component {
render() {
let sideDrawerClass = [classes.SideDrawer];
// SideDrawer will now be an array with the side drawer classes and the open class
if (this.props.showSideDrawer) {
sideDrawerClass.push(classes.Open);
}
return (
<Aux classname={classes.SideDrawer}>
<Backdrop
showBackdrop={this.props.showSideDrawer}
clicked={this.props.toggleSideDrawer}
/>
<div
className={sideDrawerClass.join(" ")}
onClick={this.props.toggleSideDrawer}
>
<div className={classes.Logo}>
<Logo />
</div>
<nav>
<NavigationItems />
</nav>
</div>
</Aux>
);
}
}
export default SideDrawer;

How to use StyledComponents theme inside of Component

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

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");

Categories

Resources