Styled components are really nice in compartmentalizing styling and keeping it close to the components that use it.
I wasn’t around for the “good old days” when we had a single master CSS file, but I can imagine how challenging it would be.
That’s why I thought it was interesting when I came across an example where I wanted to share styling across different components in a sudo-object-oriented way.
In this example, I have two components. They’re both inputs, but they’re built off of different bases (we’ll take this as granted for the sake of this example). The styling, however, is nearly identical with the second one building on the base of the first.
How could I re-use the styling with Styled-Components without duplicating code and potentially diverging in the future when I forget to update one?
What follows is a simple example demonstrating how I used css helper function within styled-components
to effortlessly reuse my css without duplicating code.1
My original styled input:
import styled from ‘styled-components’;
export const DefaultInput = styled.input`
border: 1px solid ${({error})=>( error ? `red` : `grey` )};
border-radius: 4px;
outline: none;
padding: 0.5em;
`;
Since my second component actually isn’t going to be an input
(it will be a button
), I unfortunately can’t just do:
import styled from ‘styled-components’;
export const SecondComponent = styled(DefaultInput)`
/* make changes as needed*/
`;
This would be ideal since I could simply extend the CSS I defined originally.
Enter the CSS helper function from styled components!
import styled, { css } from ‘styled-components’;
const baseInputStyles = css`
border: 1px solid ${({error})=>( error ? `red` : `grey` )};
border-radius: 4px;
outline: none;
padding: 0.5em;
`;
export const DefaultInput = styled.input`
${baseInputStyles}
`;
export const SecondComponent = styled.button`
${baseInputStyles}
/* make changes as needed*/
`;
Top comments (6)
Since my second component actually isn’t an input, I unfortunately can’t just do...
I don't understand the above statement.
Can you please explain what is the difference between your 2 examples?
Oy - thank you for pointing that out! That's a mistake on my end.
I've updated the post to reflect what I meant. Bear in mind that the use of
input
andbutton
are purely illustrative and could be anything. The bigger point is that the base elements are different and so can't simply be extended.But we can use the
css
method to create a shared UI and eliminate some duplication.Styled components has a property for this kind of use cases: styled-components.com/docs/api#as-...
If you want to keep all the styling you've applied to a component but just switch out what's being ultimately rendered (be it a different HTML tag or a different custom component), you can use the "as" prop to do this at runtime.
Good point! When I wrote this I hadn't yet found
polymorphic
components. When I did a few weeks later, I wrote about them as well: stephencharlesweiss.com/blog/2019-... :)(One point: I have had trouble with polymorphic components in my typescript app. Haven't dug into it too deeply yet, but just something to keep in mind)
Any idea how to reuse styles between vendor prefixes ? I'm building a custom audio component and want to target the slider thumb. since different browsers expose a different pseudo element, i'm having to add the same styles for each prefix.
const BaseThumbStyles = {
borderRadius: '50%',
border: 'none',
backgroundColor: 'var(--thumb-color)',
cursor: 'pointer',
position: 'relative',
boxSizing: 'border-box',
};
export const ProgressBar = styled.input
;::-webkit-slider-runnable-track,
::-moz-range-track {
${() => css(BaseTrackStyles)};
}
for anyone looking, this works