1

I am currently experiencing a structural problem with React and styled-components where I cannot find a seemingly nice solution for every case.

Here's the (quite simple) problem:

<Margin top="10%" left="5%">
    <Card>Some text</Card>
</Margin>

The Margin component extracts the margin settings from the Card component so that the Card component can be reused in other scenarios. The Margin component itself can be reused aswell.

If one wanted to make this responsive though, it would only be possible via different props like topPhone, topTablet and so on, which I find very unintuitive and hard to maintain if the responsive boundaries ever change.

So what one could do is duplicate all the content into different other components and display only the one that currently fits (e.g. react-responsive's MediaQuery component).

But in that case, the page would have a lot of overhead for different device sizes.

What would be the best way to approach this?

NikxDa
  • 4,137
  • 1
  • 26
  • 48

2 Answers2

1

Here’s an outline of the implementation I use (slimmed down), it may fit your case. It involves a little set up but helps keep responsive boundaries maintainable (which I believe is the main concern).

1) Setup an object with your desired responsive boundaries:

const screenSize = {
  sm: 576,
  md: 768,
  lg: 992,
};

2) Create a Theme to help pass those boundaries through your application via styled-components. Here I set them up with the breakpoints (media-queries) in mind, using something like Bootstrap as a guideline (These should be extended to include smMin, mdMin etc):

const theme = () => {
  return {
    xsMax: screenSize.sm - 1 + 'px',
    smMax: screenSize.md - 1 + 'px',
    mdMax: screenSize.lg - 1 + 'px',
  };
};

3) Wrap your application with your Theme as mention here.

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

4) Using styled-components’ tips-and-tricks as an example. Create an exportable media helper to make use of those Theme breakpoints (I’ll only illustrate 2 breakpoints, but you should expand this to include xsDown, smDown, lgUp, mdOnly etc etc)

export const media = {
  smDown: (...args) => css`
    @media (max-width: ${({ theme }) => theme.smMax}) {
      ${css(...args)};
    }
  `,
  mdDown: (...args) => css`
    @media (max-width: ${({ theme }) => theme.mdMax}) {
      ${css(...args)};
    }
  `,
};

5) import media and use it like a normal old media-query wrapping your responsive styling:

const MyComponent = styled('section')`
  /* Everything to be pink on screens with widths < 768px */
  ${media.smDown`
    * {
      background: papayawhip;
    }
  `};
`;

const MyOtherComponent = styled(‘li’)`
  /* Everything to be purple on screens with widths < 992px */
  ${media.mdDown`
    * {
      background: purple;
    }
  `};
`;

You can import media and reused it in Margin or any other component in your application. Responsive boundaries are maintained in one place.

Ricardinho
  • 1,319
  • 13
  • 15
  • This is a nice solution for media queries, but does not answer my question. I need to change margins which the component should not know about. The margin component itself should be reusable. Therefore, this approach is not what I was looking for. Sorry – NikxDa Dec 22 '18 at 04:28
-1

Have you checked out react-socks yet? It helps building responsive React components.

<Breakpoint topPhone only>
  <div>I will render only in topPhone</div>
</Breakpoint>

<Breakpoint topTablet only>
  <div>I will render only in topTablet</div>
</Breakpoint>

Disclaimer: I am the author of this library.

Dinesh Pandiyan
  • 5,814
  • 2
  • 30
  • 49
  • As I've described, approaches like this result in overhead for different device sizes if you compare the React output. I'm looking for a no-overhead solution. – NikxDa Dec 11 '18 at 02:02