menu
Channels
Team

Default Values: Default Props 𝐗 CSS Rules

April 8, 2019 at 9:01pm

Default Values: Default Props 𝐗 CSS Rules

April 8, 2019 at 9:01pm (Edited 11 months ago)
Hey πŸ‘‹
Something that's been on my mind for a while is how to define Default Values with Styled System. recently published this cool guide on default values and I'd like to bring up some pros and cons with this approach vs setting them as CSS Rules.
Below are two examples of the same Button Component, one setting the default values as React's defaultProps and one as Styled Component CSS Rules.
Note: This example is more complex than Bren't since the goal is to highlight pros/cons with both approaches.
Both examples below will use this Theme:
const theme = {
fontSizes: [".8125rem", ".9375rem"],
space: ["0", ".3125rem", ".625rem", ".9375rem"],
radii: [0, ".1875rem"],
colors: {
black: "#000",
white: "#fff",
gray: "#eaeaea"
}
};
theme.buttons = {
white: {
color: themeGet("colors.black")({ theme }),
backgroundColor: themeGet("colors.white")({ theme }),
borderColor: themeGet("colors.gray")({ theme }),
"&:hover": {
borderColor: themeGet("colors.black")({ theme })
}
}
};

Default Props β€” CodeSandbox Demo

const Button = styled.button`
border: 1px solid ${themeGet("colors.black")};
border-radius: ${themeGet("radii.1")};
outline: none;
line-height: 1;
padding: ${themeGet("space.1")} ${themeGet("space.2")};
&:hover {
background-color: ${themeGet("colors.white")};
color: ${themeGet("colors.black")};
}
${color}
${fontSize}
${space}
${buttonStyle}
`;
Button.defaultProps = {
backgroundColor: "black",
color: "white",
fontSize: 0,
theme
};
Notes:
  • Styles are shared in various places: some are defined as CSS Rules (border, line-height, etc), some are defined as Default Props (backgroundColor, color and fontSize) and finally there are styles in theme.buttons (3 places)
  • When defining default values with defaultProps, you don't need themeGet() to access the Theme, so that's nice πŸ‘

CSS Rules β€” CodeSandbox Demo

const Button = styled.button`
background-color: ${themeGet("colors.black")};
border: 1px solid ${themeGet("colors.black")};
border-radius: ${themeGet("radii.1")};
color: ${themeGet("colors.white")};
font-size: ${themeGet("fontSizes.0")};
line-height: 1;
outline: none;
padding: ${themeGet("space.1")} ${themeGet("space.2")};
&:hover {
background-color: ${themeGet("colors.white")};
color: ${themeGet("colors.black")};
}
${color}
${fontSize}
${space}
${buttonStyle}
`;
Button.defaultProps = {
theme
};
Notes:
  • Most of the styles are together, you don't need to scan the file up and down to grasp what the styles are
  • You need to use themeGet() to access theme properties from CSS Rules

Conclusion

  • I don't think there's necessarily the right or wrong way of setting default values
  • I wouldn't want to expose System Props to my Component just so I can style them via defaultProps. I'd like to expose them if I want those properties to be changed, as part of my Component API
  • Another possibility would be to set a default variant of black and move the styles into theme.buttons - but then where do we put shared styles? I feel like with this approach there would be too much repetition
Personally, I've been using the CSS Rules approach with the new Modulz Design System because I think it's cleaner and that it will work well across Components with different levels of complexity, and this leads to a more consistent approach throughout the codebase.
Aaaaanyways, like always, super keen to hear everyone's thoughts.
Cheers πŸ‘Š

April 8, 2019 at 9:58pm
This is great! Thanks for putting this together! I think this point is really important:
I wouldn't want to expose System Props to my Component just so I can style them via defaultProps. I'd like to expose them if I want those properties to be changed, as part of my Component API
It's tempting to throw everything into style props, but you definitely want to think about which styles are likely to change and not throw the kitchen sink of CSS into your props
Edited
like-fill
3
  • reply
  • like
On another note, what you're doing with theme.buttons.white and themeGet makes me think there's probably a more ergonomic (yet-to-be-published) way to do that sort of thing... πŸ€”
  • reply
  • like

April 9, 2019 at 7:27am
Thanks mate
What's your rationale behind this? Is it fair to say:
If you expose a System Prop, then style that via defaultProps?
I want to like that concept but I don't think it's always true. You may want to expose space but not have default margin/padding.
I'm trying to find a decent approach which can be used consistently across codebases. Then maybe have a linter for it 😜
  • reply
  • like

April 9, 2019 at 4:18pm
What's your rationale behind this?
Sorry, I'm not following... Rationale behind what?
You may want to expose space but not have default margin/padding
^^ This is I think the majority of use-cases – most of the time I wouldn't want to have default margins for example
Edited
  • reply
  • like
Sorry, that was a broad question! πŸ˜‚ I was trying to understand how you approach default values. Do you exclusively use defaultProps? My main "concern" is having the styled being split between the Styled Component and then in defaultProps, it becomes more apparent the more complex the component is.
  • reply
  • like
No worries and makes sense. I guess I tend to React like patterns as much as possible. That’s also why I like the css prop. And I guess I tend not to make components that are so complex that Default props feels problematic
like-fill
1
  • reply
  • like
thanks for your input, appreciate it
  • reply
  • like