I am new to styled components. In my React code I have some conditional rendering to change some CSS depending on if I scroll my navbar with the following code:
const [colorChange, setColorchange] = useState(false)
const changeNavbarColor = () => {
if (window.scrollY >= 80) {
setColorchange(true)
} else {
setColorchange(false)
}
}
window.addEventListener("scroll", changeNavbarColor)
<nav className={colorChange ? "navbar colorChange" : "navbar"}>content</nav>
My problem is to write the styled component for this to work.
My normal CSS looked like this:
.navbar {
/*styles...*/
}
.navbar.colorChange {
/*styles...*/
}
I started by creating the following with some styles:
const Navbar = styled.nav`
/*styles...*/
`
But how do I share the styles that are common for both navbar and colorChange; I tried appending the following to the NavBar styled component:
const Navbar = styled.nav`
/*styles...*/
.colorChange{
/*styles...*/
}
`
And then when rendering the component in React, how do I convert this line to use the styled components instead?
<nav className={colorChange ? "navbar colorChange" : "navbar"}>content</nav>
You need pass colorChange state to NavBar component.
This is NavBar declaration
const NavBar = styled.nav`
//styled for nav bar
color: ${props => props.color}
`
And use it in component
<NavBar color={colorChange ? '#fff':'#ddd'}>{children}</NavBar>
Just pass prop as dynamic value
const Navbar = styled.nav`
// navbar common css
color: ${({ color}) => color};
`
<Navbar color={colorChange ? 'red':'transparent'} />
as you commented you have multiple styles I suggest below approach just pass on prop for isColorChange
const Navbar = styled.nav`
font-size: 13px; //common style
background: ${props => (props.isColorChange ? "#6495ED" : "#2b2b2b")};
background-color: ${props => (props.isColorChange ? "#6495ED" : "#2b2b2b")};
margin-top: ${props => (props.isColorChange ? "10px" : "20px")};
padding-top: ${props => (props.isColorChange ? "5px" : "10px")};
padding-bottom: ${props => (props.isColorChange ? "5px" : "10px")};
`;
<Navbar isColorChange={true / false}></Navbar>;
Related
I use Styled-Components with React.
My code looks like this:
const StyledLink = styled.a<StyledProps>`
font-size: ${(props) => pxToRem(props.fontSize!)};
//disabled state
${(props) =>
props.disabled &&
css`
color: grey;
pointer-events: none;
`}
`
const Link = ({href, disabled, fontSize = 16, children}: Props) => {
return(
<StyledLink href={href} fontSize={fontSize} disabled={disabled}>{children}</StyledLink>
)
}
Everything works fine, however when I inspect my elements I see:
<a href="#" font-size="16" disabled>Some Link</a>
I want fontSize and disabled to be props that target only Styled-Components. I don't want them to applied for React element.
Is there a better way of doing that without changing props names to something like styledFontSize and styledDisabled?
styled-components provides transient props for those who wants to avoid property passing down to DOM or React node where the property name should have $ (dollar sign) prefix.
Using $ transient props:
const StyledLink = styled.a<StyledProps>`
font-size: ${(props) => pxToRem(props.$fontSize!)};
//disabled state
${(props) =>
props.$disabled &&
css`
color: grey;
pointer-events: none;
`}
`
const Link = ({href, disabled, fontSize = 16, children}: Props) => {
return(
<StyledLink href={href} $fontSize={fontSize} $disabled={disabled}>{children}</StyledLink>
)
}
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 new to React, trying to integrate some animations. I'm using Gatsby.js framework.
const LeadHeading = styled(animated.h1)`
font-weight: bold;
font-size: 3rem;
font-family: ${props => props.theme.fontSecondary};
margin-bottom: 0;
line-height: 2.5rem;
color: #FFF3D8;
const IndexPage = ({menuOpen}) => {
const h1Animation = useSpring({
opacity: menuOpen ? '0' : '1'
})
return (
<>
<Layout>
<Section className="hero is-fullheight">
<div className="hero-body container is-flex">
<LeadHeading
style={h1Animation}
>
some heading
</LeadHeading>
</div>
</Section>
</Layout>
</>
)
}
export default IndexPage
The menu status is managed in the "layout" component via the useState hook.
const [menuOpen, setMenuOpen] = useState(false)
Basically, I just want to fadeout the h1 when the menu pops up, since it doesn't look good due to the transparency of the menu.
Appreciate your help.
const LeadHeading = styled(animated.h1)`
font-weight: bold;
font-size: 3rem;
font-family: ${props => props.theme.fontSecondary};
margin-bottom: 0;
line-height: 2.5rem;
color: #FFF3D8;
`
const IndexPage = ({menuOpen}) => {
const h1Animation = useSpring({
opacity: menuOpen ? '0' : '1'
})
return (
<>
<Layout>
<Section className="hero is-fullheight">
<div className="hero-body container is-flex">
<LeadHeading
style={h1Animation}
>
some heading....
</LeadHeading>
</div>
</Section>
</Layout>
</>
)
}
export default IndexPage
EDIT// The menu status is managed in the "layout" component via useState hook.
But it should be possible, to pass the data to "IndexPage" right?
Ok I thought I can skip the animated part in the render method, since I use it above in the styled component variable. (sry I forgot to mention that in my previous post).
Your approach was one of my first approaches but it didnt work.
export const RedHeader = styled.div`
color: red;
border: 1px solid blue;
background-color: gray;
`;
function Header(className) {
return (
<RedHeader className={className}>
this is styled component example
<p>test</p>
</RedHeader>
)
}
export default Header;
I have red the cdocumentation but i can't figure out, why should we use className as a props and after that in className={className}?
When using styled components, there should be no need to use className (which renders as class attribute in HTML) anymore. In your example, you pass className to the styled component, but the styled component does not use it in any way.
You can pass properties to your styled components if you want dynamic styling like you would do with class names in classic CSS.
Example with style that depends on a class name:
const RedHeader = styled.div`
color: red;
&.active {
color: blue;
}
`
Example with props:
const RedHeader = styled.div`
color: ${props => props.active ? 'blue' : 'red'}
`
function Header({ active }) {
return (
<RedHeader active={active}>
example
</RedHeader>
)
}
I want to take styling from the component 'Tab' which is a react-router-dom Navlink and apply it to my new component 'DropdownTab' which is a 'div'. How can I inherit the styling without making it a NavLink? I want to do this to avoid duplicate lines of code.
const Tab = styled(NavLink)`
padding: 0 20px;
height: ${variables.height};
line-height: ${variables.height};
`;
// Should be the component 'Menu' and is now the component NavLink
const DropdownTab = styled(Tab)`
`;
Perhaps you can use as?
const DropdownTab = styled(props => <Tab as="div" {...props} />)`
/* additional styles */
`;
That's ugly though, so maybe you can just extract the common styles into a variable:
const commonStyles = `
/* common styles */
`
const Tab = styled(NavLink)`${commonStyles}`
const DropdownTab = styled('div')`${commonStyles}`
If you have prop-based style in your component (i.e color: ${props => props.color}, you'd need to use css helper:
import styled, { css } from 'styled-components'
const commonStyles = css`
color: ${({ isActive }) => isActive ? 'red' : 'blue' };
`
...
Why is DropdownTab a div?
Based on your code, DropdownTab is a Tab. You've used the extending styles concept of styled-components and you've done it right.