Search code examples
javascriptcssreactjsstyled-components

How to style my own components (responsive header) with styled-components?


I'm trying to build a responsive header component. It should display all the nav links using display:inline-block when in desktop, and it should display all the nav links using display:block when on mobile.

Note: I'm using react-responsive to do media queries, so:

import Responsive from 'react-responsive';

function Mobile(props) {
  return(<Responsive {...props} maxWidth={800}/>);
}

function Desktop(props) {
  return(<Responsive {...props} minWidth={801}/>);
}

<Mobile> will render on mobile, and <Desktop> will render on desktop. That part is working fine. I'm just not able to change the styled accordingly.

Note that all code below is inside Header.js.

My current approach, which is not working, is the following:

Header component

Is the one that is exported and consumed by the rest of my code. It render the <MobileHeader> on mobile and <DesktopHeader> on desktop. Both are styled components.

function Header(props) {
  return(
    <React.Fragment>
      <Mobile>
        <MobileHeader
          authUser={props.authUser}
        />
      </Mobile>
      <Desktop>
        <DesktopHeader
          authUser={props.authUser}
        />
      </Desktop>
  </React.Fragment>
  );
}

HeaderBase component:

Both of my styled <MobileHeader> and <DesktopHeader> should style the HeaderBase component, which is the following (simplified):

function HeaderBase(props) {
  return(
    <header>
    <div>

      <h1>Header</h1>
      <ul>
        <li>
          <Link to={ROUTES.HOME}>Home</Link>
        </li>
        <li>
          <Link to={ROUTES.ACCOUNT}>Account</Link>
        </li>
      </ul>

    </div>
  </header>
  );
}

QUESTION:

MobileHeader and DesktopHeader components:

I guess here is where the problem is. Am I allowed to reference html tags inside a styled custom component as I did with the li ? Because that doesn't seem to work. That works when I'm styling regular html tags, though.

Do you guys recommend another approach to this? My final goal is to have an overlay side nav bar that you click and it comes from the left when the user is on mobile. On desktop I'll have a regular inline-block navbar. Since the links will be the same on each case, I'm thinking I should reuse the HeaderBase and use styled-components to style it accordingly.

const MobileHeader = styled(HeaderBase)`
  li {
    display: block;
  }
`;

const DesktopHeader = styled(HeaderBase)`
  li {
    display: inline-block;
    padding: 5px;
    margin: 0;
    box-sizing: border-box;
  }
`;

Solution

  • Just found out what was wrong:

    As per the styled-components docs:

    If you use the styled(MyComponent) notation and MyComponent does not render the passed-in className prop, then no styles will be applied. To avoid this issue, make sure your component attaches the passed-in className to a DOM node:

    So I needed a "parent" html node rendered by my component to receive the className props with the styles from the styled components:

    function HeaderBase(props) {
      return(
        <header>
        <div className={props.className}>  // <----- NOW IT WORKS!
    
          <h1>Header</h1>
          <Mobile>☰ I am mobile header</Mobile>
          <ul>
            <li>
              <Link to={ROUTES.HOME}>Home</Link>
            </li>