Search code examples
javascriptreactjstypescriptstyled-components

Styled components media query mixin seems to ignore props


I created a media query that looks like this:

media.ts

export const breakpoints = {
  sm: 420,
  md: 768,
  lg: 992,
  xlg: 1200,
};

export const media = Object.keys(breakpoints).reduce((acc, label) => {
  acc[label] = (literals: TemplateStringsArray, ...placeholders: any[]) =>
    css`
      @media (min-width: ${breakpoints[label]}px) {
        ${css(literals, ...placeholders)};
      }
    `.join('');
  return acc;
}, {} as Record<keyof typeof breakpoints, (l: TemplateStringsArray, ...p: any[]) => string>);

Which will work like this:

 * @example
 * const StyledComponent = styled.div`
 *  background-color: red;
 *
 *  ${media.sm`
 *    background-color: blue
 *  `}
 *
 *  ${media.md`
 *    background-color: green;
 *  `}

However, when I pass props into the media query, it seems to get ignored. Example here:

<GreetingContainer isTesting>
...
</GreetingContainer>

const GreetingContainer = styled.div`
  display: flex;
  background: green;

  ${media.md`
    flex-direction: row;
  `}

  ${media.lg`
    background: ${(props: { isTesting: any }) => (props.isTesting ? 'blue' : 'red')};
  `}
` as any;

It seems like in my media.lg, the whole thing gets ignored completely. Does anyone know what's going on? Is there a workaround or a fix in the utility I've written?

I'm seeing my css looks like this:

enter image description here

which is very much not what I want. What seems to be the issue here?


Solution

  • The culprit is the ending .join(''), which forces the output of css template tag function to be converted as a string, hence the "inlining" of your function body in the CSS rule.

    Just remove it to restore your expected behaviour:

    export const media = Object.keys(breakpoints).reduce((acc, label) => {
      acc[label] = (literals: TemplateStringsArray, ...placeholders: any[]) =>
        css`
          @media (min-width: ${breakpoints[label]}px) {
            ${css(literals, ...placeholders)};
          }
        `; //.join(""); // Let the output remain a function
      return acc;
    }, {} as Record<keyof typeof breakpoints, (l: TemplateStringsArray, ...p: any[]) => string>);
    

    Demo: https://codesandbox.io/s/eager-benji-qepx9o?file=/src/App.tsx