Recently on a project we worked on the new set of form components for internal library.
Our stack includes styled-components
and I want to share an approach, which might be useful for someone. No knowledge behind basics (styled
and css
utilities) of aforementioned library is needed.
Let's say we have an input component, with border and border-radius configured. We assume that it can resemble complex structure, so we'll use simple div as a wrapper
const StyledInputContainer = styled.div`
border: 1px solid black;
border-radius: 4px;
`
const Input = () => {
return <StyledInputContainer>
<input /> // Just for illustrative purposes, we won't build real Input here
</StyledInputContainer>
}
Fine. What if we want to allow user to remove value by clicking on cross button? We can add it to our Input
+ const StyledClearButton = styled.button`
+ // other styles for button
+ `
const StyledInputContainer = styled.div`
border: 1px solid black;
border-radius: 4px;
+ display: flex;
+ justify-content: space-between;
`
const Input = () => {
return <StyledInputContainer>
<input />
+ <StyledClearButton>X</StyledClearButton>
</StyledInputContainer>
}
Having button hanging all the time in the input might be distracting for user, we can show it only if container is hovered.
const StyledClearButton = styled.button`
+ visibility: hidden;
// other styles for button
`
const StyledInputContainer = styled.div`
border: 1px solid black;
border-radius: 4px;
display: flex;
+ &:hover {
+ ${StyledClearButton} { // Way to create css cascade
+ visibility: visible;
+ }
+ }
`
const Input = () => {
return <StyledInputContainer>
<input />
<StyledClearButton>X</StyledClearButton>
</StyledInputContainer>
}
Now the button will be visible only if container is hovered.
We can even add props to this setup. For example, if our input has errors, we want it to have red border.
const StyledClearButton = styled.button`
visibility: hidden;
// other styles for button
`
const StyledInputContainer = styled.div`
- border: 1px solid black;
+ border: 1px solid ${props.error ? 'red' : 'black'};
border-radius: 4px;
display: flex;
&:hover {
${StyledClearButton} {
visibility: visible;
}
}
`
const Input = () => {
+ // error state is handled here
- return <StyledInputContainer>
+ return <StyledInputContainer error={error}>
<input />
<StyledClearButton>X</StyledClearButton>
</StyledInputContainer>
}
Until now it was pretty common development path for styled-components
adoption. But here is the tricky part. In a very different module we want to have a TextArea
component, which will have same border, border-radius (background color, hover/active states, etc.) as our Input
. But it shouldn't have ClearButton
. So the question is - how to exploit what is reusable here?
Answer is simple - put common part to the function and use it to populate different styled wrappers. We can do it first for the Input
const StyledClearButton = styled.button`
visibility: hidden;
// other styles for button
`
+ export const getCommonInputStyles = (props, closeButtonCmp) => css`
+ border: 1px solid ${props.error ? 'red' : 'black'};
+ border-radius: 4px;
+ ${closeButtonCmp && css`
+ &:hover {
+ ${closeButtonCmp} {
+ visibility: visible;
+ }
+ }
+ `}
+ `
const StyledInputContainer = styled.div`
- border: 1px solid ${props.error ? 'red' : 'black'};
- border-radius: 4px;
display: flex;
- &:hover {
- ${StyledClearButton} {
- visibility: visible;
- }
- }
+ ${props => getCommonInputStyles(props, StyledClearButton)}
`
const Input = () => {
// error state is handled here
return <StyledInputContainer>
return <StyledInputContainer error={error}>
<input />
<StyledClearButton>X</StyledClearButton>
</StyledInputContainer>
}
And now we can use extracted styles in whatever else component we want. Like mentioned above TextArea
const StyledTextAreaContainer = styled.div`
${props => getCommonInputStyles(props)}
`
const TextArea = () => {
// error state is handled here
return <StyledTextAreaContainer error={error}>
<textarea />
</StyledTextAreaContainer>
}
You can see that since TextArea doesn't contain clear button we passing it to getCommonInputStyles
That's it. I hope you'll find it useful in your daily work with such great library as styled-components
Top comments (0)