35

I'm using styled-components to build my components. All style properties which accept custom values are reused throughout my components (as it should be). With that in mind, I'd like to use some sort of global variables so that updates will propagate to all components without needing to update each style individually.

Something like this:

// Variables.js

var fontSizeMedium = 16px;

// Section.js

const Section = styled.section`
  font-size: ${fontSizeMedium};
`;

// Button.js

const Button = styled.button`
  font-size: ${fontSizeMedium};
`;

// Label.js

const Label = styled.span`
  font-size: ${fontSizeMedium};
`;

I guess I'm getting the syntax wrong though? Also, I know global variables are not recommended in Javascript land, but in design land reusing styles across components is an absolute must. What are the trade-offs here?

colmtuite
  • 4,311
  • 11
  • 45
  • 67

3 Answers3

50

I eventually figured this out, so here's how you can do it, at least if using React.

You need to define the variables in one file and export them.

// Variables.js

export const FONTSIZE_5 = '20px';

Then you need to import those variables into each component file.

// Button.js

import * as palette from './Variables.js';

Then you can use the variables in your styled-components like this:

const Button = styled.button`
  font-size: ${palette.FONTSIZE_5};
`;
colmtuite
  • 4,311
  • 11
  • 45
  • 67
  • 7
    Isn't this just for static theming though? With this solution, you can't really render on a change to the variable. I'd go with @Ricardinho 's answer as this allows you to update the theme dynamically; through an actual object. – Kevin Frostad Jan 22 '19 at 15:01
  • 1
    I agree in most cases that using the `` is the best way. In some cases (ex. defining responsive breakpoints), it seems static variables could be helpful. In most cases though, you get a lot more power using the `` (ex. light/dark mode switching, customizing elements at deeper levels using nested `ThemeProvider`, etc) – plong0 Feb 02 '21 at 23:54
50

Wrapping a <ThemeProvider> around your application may help:

https://www.styled-components.com/docs/advanced#theming

const theme = {
  fontColour: 'purple'
}

render() {
  return (
    <ThemeProvider theme={theme}>
      <MyApplication />
    </ThemeProvider>
  )
}

That will give all child styled-components access to the theme like so:

const MyApplication = styled.section`
  color: ${props => props.theme.fontColour}
`

Or

const MyFancyButton = styled.button`
  background: ${props => props.theme.fontColour}
`

Or access the theme via https://www.styled-components.com/docs/advanced#getting-the-theme-without-styled-components

Ricardinho
  • 1,319
  • 13
  • 15
  • 2
    This should be an accepted answer. If you want to have an scss like variables in styled components then you should use `theme` object which holds all your global settings and pass it to `` wrapper. – Grzegorz Gralak Jan 04 '19 at 15:45
5

Your final solution works for 2 two reasons:

  1. Simply declaring a variable in a file does not attach it to the global scope for the entire app, so other files are unaware of it unless imported in.
  2. 16px is not a valid value. It needed to either be wrapped in quotes to make it a string (like you did with '20px'), or the px needed to be removed.

I ran into a similar situation, except I needed my variables to be numbers instead of strings, and this also works:

const CELL_SIZE = 12;
const ROWS = 7;
const CELL_GAP = 3;

const BannerGrid = styled.div`
  display: grid;
  grid-template-columns: repeat(auto-fit, ${CELL_SIZE}px);
  grid-template-rows: repeat(${ROWS}, ${CELL_SIZE}px);
  grid-column-gap: ${CELL_GAP}px;
  grid-row-gap: ${CELL_GAP}px;
  grid-auto-flow: column;
`;
Laney Smith
  • 51
  • 1
  • 3