Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Theme defaults with styled components


I am starting to use styled-components.

I have some challenges for which I know a solution in SASS, but I am not sure how to tackle with styled-components.

The challenge is: How to setup the defaults values for all the different variables in a Theme.

Here it is a PoC:

  • We are using a theme.variables.js file for general/global variables like colors, margins, paddings, fonts, etc.
  • Each component has it own theme object. This object contains the variables/properties specific for the component and it uses vars from theme.variables.js.
  • Last but not least, we have a theme.js file that exports an object with all variables from theme.variables.js and with the theme object from each and every component. This object is the one that should be passed as a prop in the <ThemeProvider />.

With this approach we have 2 levels to customise a theme:

  • First, we have the global theme variables. Here we setup brand identity variables such as brand colors, fonts, spacing, etc. As far as each component theme variables are componsed from this global theme variables, all components should get a nicely styled with this brand values.
  • Second we have the component theme variables. Here we can go down to a much more granular custimisation on a component basis.

I think it worth mentioning that ideally we should only use the 1st level of customisation. This way we keep a more consistent UI.

Please leave your feedback to this concept in the comments 😄

  • Do you see any pitfalls on this design?
  • How do you think it can be improved?
  • Do you know of any other approach to solve this challenge?
  • Any other feedback you consider is valuable 😉
import styled from 'styled-components'
import themeVars from 'theme.variables'
const Button = styled.button`
background-color: ${({theme}) => theme.button.backgroundColor};
border: none;
border-radius: ${({theme}) => theme.button.radius}px;
color: white;
cursor: pointer;
padding: ${({theme}) => theme.button.padding}rem;
transition: background-color 400ms ease, box-shadow 400ms ease, color 400ms;
&:hover, &:focus {
background-color: ${({theme}) => theme.button.hoverBackgroundColor};
&:active, &.active {
box-shadow: inset -1px -1px 0 #444;
&:focus { outline: none; }
export const buttonTheme = {
button: {
backgroundColor: themeVars.colors.primary,
hoverBackgroundColor: themeVars.colors.primaryDark,
padding: themeVars.layout.gutter
Button.defaultProps = { theme: buttonTheme }
export default Button
import themeVariables from 'theme.variables'
import { buttonTheme as button } from 'atoms/Buttons/Button'
export default Object.assign({},
import Color from 'color'
const colors = {
/** @color Primary brand color */
primary: '#64C1C7',
/** @color Secondary brand color */
secondary: `#FF6A00`,
/** @color Secondary brand color */
text: `#3F3E3E`,
// colors variations
// percentage
darkerPercent: 0.2,
darkPercent: 0.1,
lightPercent: 0.2,
lighterPercent: 0.2
// colors variations
colors.primaryDark = Color(colors.primary).darken(colors.darkerPercent).string()
colors.secondaryDark = Color(colors.secondary).darken(colors.darkerPercent).string()
const global = {
radius: 3
const layout = {
gutter: 0.6
export default { colors, global, layout }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.