Skip to content

Instantly share code, notes, and snippets.

@nickpiesco
Created October 16, 2015 14:46
Show Gist options
  • Save nickpiesco/9bef21b4f9e236b4430e to your computer and use it in GitHub Desktop.
Save nickpiesco/9bef21b4f9e236b4430e to your computer and use it in GitHub Desktop.
DRY out Media Queries with React and Radium

Here at Bloomfire, we’re loving building new components with React. We’re even going all in with using ES6 modules and inline styles. (‘Inline styles?!’ I hear you say? Don’t knock it ’til you’ve tried it.)

There’s a lot of cool stuff we can do with CSS that we can’t do with inline styles, though; and that’s where Radium comes in. Radium not only provides a handy way to style :hover, :focus, and :active states, but it also deftly handles media queries. If you’re using inline styles in React and not using Radium, you should. I’ll give you a minute to go look it over – here’s the link again.

Back? Okay.

We create a style object in each of our React components, which we then reference in the JSX below. Here’s a super-stripped-down example:

// [myAwesomeButton.js]

const styles = {
  button: {
    backgroundColor: '#005496'
  },
  buttonText: {
    color: 'white'
  }
};

export default class MyAwesomeButton {
  render () {
    return (
      <button style={styles.button}>
        <span style={styles.buttonText}>
          {this.props.buttonText}
        </span>
      </button>
    );
  }
}

Variables

In our existing application, we keep all our colour variables in a single Sass partial so we can share values across components and not have to chase them down every time we want to change something. This should look pretty familiar:

// [_colors.scss]

$brand-blue: #005496;
$brand-orange: #f37021;

$brand-color: $brand-blue;
$accent-color: $brand-orange;

We can do that with React too – we create a component that contains the colours we need and then import it wherever we need it:

// [colors.js]

const baseColors = {
  brandBlue: '#005496',
  brandOrange: '#f37021'
};

export default {
  brandColor: baseColors.brandBlue,
  accentColor: baseColors.brandOrange
};
// [myAwesomeButton.js]

import colors from 'path/to/colors';

const styles = {
  button: {
    backgroundColor: colors.brandColor
  },
  buttonText: {
    color: 'white'
  }
};

Media Queries

Radium nestles media queries snugly in your style object:

const styles = {
  hideThisOnBigScreens: {
    display: 'block',
    '@media screen and (min-width: 64em)': {
      display: 'none'
    }
  }
};

In the Sass world, we do the same thing with media queries that we do with colours – put them in a separate partial for easy cross-component sharing and to keep all the maintenance in one place.

// [_media-queries.scss]

$breakpoint-large: '@media screen and (min-width: 64em)';
$breakpoint-small: '@media screen and (max-width: 20em)';

So we can set up a media queries component just like we did for colours:

// [mediaQueries.js]

export default {
  breakpointLarge: '@media screen and (min-width: 64em)',
  breakpointSmall: '@media screen and (max-width: 20em)'
};

However, this bombs out:

// [somethingForBigScreens.js]

import mediaQueries from 'path/to/mediaQueries';

// This doesn’t work
const styles = {
  hideThisOnBigScreens: {
    display: 'block',
    mediaQueries.breakpointLarge: {
      display: 'none'
    }
  }
};

That’s because a naked variable can be the value of an object’s property, but not the key.

ES6 to the rescue! ES6 brings us computed property names, which allow us to use an expression like our variable here – as long as we wrap it in square brackets.

// [somethingForBigScreens.js]

import mediaQueries from 'path/to/mediaQueries';

// This works!
const styles = {
  hideThisOnBigScreens: {
    display: 'block',
    [mediaQueries.breakpointLarge]: {
      display: 'none'
    }
  }
};

Now that we can use variables for both keys and values, we can set them up in one central location to keep our code nice, DRY, and easy to maintain.

@codeithuman
Copy link

What does the CSS output of this look like? What happens when the screen resizes?

@nickpiesco
Copy link
Author

@codeithuman Slightly more verbose answer than Twitter allows: 😄 Radium attaches a listener for resize events and merges/swaps in the new styles based on window.matchMedia. You wouldn’t know by looking at the static output that a media query has been applied, since it’s just one string replaced with another. You can have a play-about with the main content area on Bloomfire Community to see how this works in the real world, and if you’re interested in what’s going on under the hood, you can check out Radium’s implementation here. Thanks for getting in touch!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment