im trying to create a component whose css outputs a box-shadow with a number of shadows to create a stacked paper effect. Im trying to do this with styled-components. Not having much joy passing the css to the prop. Thanks in advance.
import React from 'react'
import styled from 'styled-components'
const shadows = []
const shadowMixin = (shadow) => {
let i ='';
for(i = 0; i <= shadow; i++){
shadows.push(`${i}px ${i}px ${i % 2 ? "red" : "black" }`)
}
}
shadowMixin(10)
console.log([...shadows].join(','))
const Input = styled.input.attrs(({ size }) => ({
// we can define static props
type: "password",
// or we can define dynamic ones
boxShadow: size || "2px 2px black"
}))`
box-shadow: ${props => props.boxShadow}
`
// const Wrapper = styled.div`
// `
export default() => <Input size={[...shadows].join('')} />;
You are applying your box shadow as an element attribute rather than as a style.
Try this instead:
const Input = styled.input.attrs(() => ({
type: "password"
}))`
box-shadow: ${props => props.boxShadow || "2px 2px black"};
`
...and then pass the boxShadow prop:
export default () => <Input boxShadow={[...shadows].join('')} />
Related
My goal is to have responsive font-size in a <textarea> element, for both the user input text and the placeholder text. I am using Styled Components in React with Typescript.
I have achieved responsive font-size for the input text 🙂, but the same script does not affect the placeholder text 🙁.
const DynamicTextInput = styled.textarea.attrs((props: {
fontSize: string}) => props)`
font-size: ${(props) => props.fontSize};
&::placeholder {
font-size: ${(props) => props.fontSize};
}
`;
const placeholderText = 'Hello Placeholder!...';
const [count, setCount] = useState(0);
const newFontSize = 140 - (count/4) + 'px';
<DynamicTextInput
placeholder={placeholderText}
onChange={e => setCount(e.target.value.length)}
fontSize={newFontSize}
/>
note: the placeholder text itself needs to be a variable.
Can you see how I can get the placeholder text font-size to respond to the same variable that is successfully manipulating the input text font-size?
Thank you for your time.
The best way to make this:
export const DynamicTextInput = styled.textarea.attrs({
placeholderTextColor: "red"
});
or just remove & from &::placeholder
const DynamicTextInput = styled.textarea.attrs((props: {
fontSize: string}) => props)`
font-size: ${(props) => props.fontSize};
::placeholder { // changed
font-size: ${fontSize}; // changed
}
`;
I am using react and styled-components.
I want to apply the style defined in the dataList when I pass the page name (home,group) to the body component as a props.
I would like to apply the home style of dataList to the box when home is passed in props, and the group style of dataList to the box when group is passed.
I tried to implement it in my own way, but an error occurs at the dataList location.
code
import React from "react";
import styled from "styled-components";
type Props = {
type: "home" | "group";
};
export const Body: React.FC<Props> = ({ children, type }) => {
const dataList = {
home: {
gridTemplateAreas: 'header''body',
gridTemplateRows: 30px calc(100vh - 100px),
padding: 30
},
group: {
gridTemplateAreas: 'header''menu''body',
gridTemplateRows: 30px calc(100vh - 70px),
padding: 30
}
};
const data = dataList[type];
return <Box props={data}>{children}</Box>;
};
const Box = styled.div<{ props: any }>`
display: grid;
grid-template-areas: ${(props) => props.gridTemplateAreas};
grid-template-rows: ${(props) => props.gridTemplateRows};
padding-left: ${(props) => props.padding};
`;
You have to pass data as props in Box component. It would be like this:
const data = dataList[type];
return <Box {...data}>{children}</Box>;
Here is working demo: https://codesandbox.io/s/weathered-fire-7soy9?file=/src/Body.tsx:458-528
Is it possible to use the spread operator with a styled component in React Native?
I have this component:
const StyledHeaderText = styled.Text`
fontFamily: ${props => props.theme.font};
fontSize: ${props => props.theme.fontSizeSubtitle};
color: ${props => (props.lightMode) ? props.theme.fontColor : props.theme.fontPrimaryColor}
`;
But lets say that in my theme, I have an object that has both the fontFamily and the fontSize, and I re use all over the app. I would like to be able to know if I can do something like this, which currently it is not working:
const StyledHeaderText = styled.Text`
...${props => props.theme.fontHeader};
color: ${props => (props.lightMode) ? props.theme.fontColor : props.theme.fontPrimaryColor}
`;
This would be useful too setting up elevation in iOS for example, since I have to setup 4 styles.
Thanks
You can use the css helper function to generate the specific css and return it as a template literal.
import styled, {css} from 'styled-components/native'
const GlobalStyles = css`
fontFamily: ${props => props.theme.font};
fontSize: ${props => props.theme.fontSizeSubtitle};
`
const StyledHeaderText = styled.Text`
${GlobalStyles}
// Other Styles
`
or conditionally as
const StyledHeaderText = styled.Text`
${props => props.theme.fontHeader ? GlobalStyles : 'fontSize: 14'}
// Other Styles
`
In React.js you can use the spread operator override multiple styles
Here is a link to a code example
const StyledText = styled.div`
/* Normal styles */
color: blue,
background-color: white,
/* Fields to override with object from props */
${({ styleOverrides }) => ({ ...styleOverrides })}
`;
You can also return objects directly from interpolations function, and they'll be treated as inline styles.
const StyledHeaderText = styled.Text`
${props => ({...props.theme.fontHeader})};
color: ${props => (props.lightMode) ? props.theme.fontColor props.theme.fontPrimaryColor}
`;
or
const StyledHeaderText = styled.Text`
${props => props.theme.fontHeader};
color: ${props => (props.lightMode) ? props.theme.fontColor props.theme.fontPrimaryColor}
`;
for more details : reference
To expand on previous answers you can also do the following:
import styled, {css} from 'styled-components/native'
// with theme
const GlobalStyles = css`
fontFamily: ${ ({theme}) => theme.font };
fontSize: ${ ({theme}) => theme.fontSizeSubtitle };
`
// Without theme using inherited props
const GlobalStyles = css`
fontFamily: ${ ({font}) => font };
fontSize: ${ ({fontSizeSubtitle}) => fontSizeSubtitle };
`
// if you wanted it to be conditional
const GlobalStyles = css`
fontFamily: ${ ({font}) => font || 'roboto' };
fontSize: ${ ({fontSizeSubtitle}) => fontSizeSubtitle || '14px' };
`
const StyledHeaderText = styled.Text`
${GlobalStyles}
// Other Styles
`
// same can also be done with regular styled components:
export const HeaderText = styled.p`
fontSize: ${ ({fontSizeSubtitle}) => fontSizeSubtitle || '14px' };
`
// Useage would be in your component would be like:
import react from react;
import { HeaderText } from '../component/styles'
export const FooComponent = memo(({ destructuredProps }) => {
// some other code
return (
<>
<HeaderText className={fooClass} fontSize='18px'> Here's my sample text! </HeaderText>
<>
)});
I'm learning React and i just founded about styled-components and i would like to refactor my code into styled components.
Maybe i didn't understand it at all but i'm trying to make add/remove class on "toggle"
For example:
button--active
Here is what i've tried so far:
render() {
const {active, toggleHamburgerActive } = this.props;
return (
<div>
<HamburgerButtonContainer active={active} onClick={toggleHamburgerActive}/>
</div>
styles:
const buttonStyles = css`
border: 1px solid red;
`;
const getButtonStyles = active => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const hamburgerActiveStyles = css`
border: 10px solid green;
`;
export const HamburgerButtonContainer = styled.button`
${getButtonStyles}
`;
#EDIT
To make it more clear. active is changing on click but styles are not.
I think you just forgot to destructure your props:
const getButtonStyles = /* this here ---> */({active}) => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const getButtonStyles = /* props is passed here, not only active ---> */props =>
You can access props by passing a callback in an expression as you did.
styled.button`
${props => ...} // you passed the callback here, so props is passed to it, not only active
`
Or if you prefer
styled.button`
${props => getButtonStyles(props.active)}
`
You haven't called your function using active as a param. And You should organise your code like below to pass the active as a prop.
const HamburgerButtonContainer = ({ onClick, active }) => {
const buttonStyles = `
border: 1px solid red;
`;
const getButtonStyles = (active) => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const hamburgerActiveStyles = `
border: 10px solid green;
`;
const StyledHamburgerButtonContainer = styled.button`
${getButtonStyles(active)}
`;
return <StyledHamburgerButtonContainer onClick={onClick} />;
};
i have the componet like below, when isOpen state true then should add margin-top 0, margin-bottom: 0, margin-right and margin-left: 4px. if isOpen state false then add margin-right: 4px and margin-bottom: 4px.
below is my code,
function Parent() {
return (
<Wrapper isOpen={isOpen}/>
//Some content
</Wrapper>
);
}
const Wrapper = styled(somediv)<{ isOpen: boolean | undefined;}>`
width: ${props => (props.isOpen ? '32px' : '40px')};
margin: 0 4px; //should modify this based on isOpen true or not.
`;
Could someone help me with this? Thanks.
Using the same styled component approach as you used.
It will work like following:
function Parent() {
return (
<Wrapper isOpen={isOpen}/>
//Some content
</Wrapper>
);
}
const Wrapper = styled(somediv)<{ isOpen: boolean | undefined;}>`
width: ${props => (props.isOpen ? '32px' : '40px')};
margin: ${props => (props.isOpen ? '0 4px' : '0 4px 4px 0')};
`;
Something like this?
<Wrapper isOpen={isOpen} style={{ isOpen===true?
{marginRight:'0px';marginLeft:'4px'} : {marginRight:'4px';marginLeft:'4px';} }}/>
//Some content
</Wrapper>
Probably the easiest way would be to create two object each one with different properties and add them with inline styles.
const styles1 = {};
const styles2 = {};
<Wrapper style={{isOpen ? styles1 : styles2}}/>
//Some content
</Wrapper>
I'm not sure if I understand correctly but using ternary operator it should look like this
const Wrapper = styled(somediv)<{ isOpen: boolean | undefined;}>`
width: ${props => (props.isOpen ? '32px' : '40px')};
margin: ${props => (props.isOpen ? '0 4px' : '0 4px 4px 0')}
`;
If you want to use className instead of inline-styling, I recommend using makeStyles from Material UI as below
// with npm
npm install #material-ui/styles
and then,
import React, {useState} from 'react';
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
myClass: {
marginBottom: isOpen => isOpen ? 4 : 0,
marginTop: 4,
width: isOpen => isOpen ? 32 : 40
}
}))
const Parent = () => {
const [isOpen, setOpen] = useState(false)
const classes = useStyles(isOpen)
return <div className={classes.myClass} />
}
Then you can use the same for other attributes and classes.