DEV Community

Cover image for Advanced Usage of Styled Components for your React App - Part 1
Olena Drugalya
Olena Drugalya

Posted on • Edited on

Advanced Usage of Styled Components for your React App - Part 1

In my previous post about styled components I wrote about the general features of Styled Components, how to set up and use them and why to use them in your React application.

This post will cover and show some advanced usage of Styled Components, so you will have more wide understanding of their flexibility and probably could learn and use some techniques.

As we know already, styled-components is a library, which helps you to create components already with a style. It removes the mapping between components and styles. This means that when you're defining your styles, you're actually creating a normal React component, that has your styles attached to it.

So, let's get to practice and learn new features on the way. We are going to create a hamburger menu, which we can use for responsive application for mobile.

Our menu will be a separate styled component, which in its turn will be created from smaller styled components. Menu will consist of a MenuButton and MenuNavigation components.
We create a file called "Menu.js" and add the following code to it:



export const Menu = () => {
  return (
    <>
      <MenuButton>
        <Line></Line>
        <Line></Line>
        <Line></Line>
      </MenuButton>
      <MenuNavigation>
        <NavList>
          <NavItem>
            <NavLink href="/">Home</NavLink>
         </NavItem>
         <NavItem>
            <NavLink href="/">About</NavLink>
         </NavItem>
       </NavList>
     </MenuNavigation>
    </>
  );
}


Enter fullscreen mode Exit fullscreen mode

Next step is styling. We create a file called "Menu.styles.js" and add there the following code:



import styled from "styled-components";

export const MenuButton = styled.div`
  cursor: pointer;
  width: 3rem;
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
`;

export const Line = styled.div`
  width: 80%;
  height: 3px;
  background-color: white;
  margin: 0.2rem;
`;

export const MenuNavigation = styled.div`
  position: fixed;
  width: 200px;
  max-width: 70%;
  height: 100%;
  left: 0;
  margin-top: 1.4rem;
  z-index: 200;
  background-color: white;
  padding: 1rem 2rem;
  transition: all 0.7s ease;
  box-shadow: 0px 8px 30px rgba(0, 0, 0, 0.2);
`;

export const NavList = styled.ul`
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  align-items: center;
`;

export const NavItem = styled.li`
  margin: 5px 0;
  box-sizing: border-box;
  width: 100%;
  display: block;
`;

export const NavLink = styled.a`
  color: #8f5c2c;
  text-decoration: none;
  width: 100%;
  box-sizing: border-box;
  display: block;
  padding: 0.5rem;
`;


Enter fullscreen mode Exit fullscreen mode

Afterwards we need to import all created styled components to out Menu.js file so we can use them:



import {
  MenuButton,
  Line,
  MenuNavigation,
  NavList,
  NavItem,
  NavLink
} from "./Menu.styles";


Enter fullscreen mode Exit fullscreen mode

So, these are some general styles we have added to every component in out application.
For now our navigation links look exactly the same, but what if we want About link to be different?

Changing style based on Props

Since our styled NavLink is a component, it accepts props under the hood. We can pass a function ("interpolations") to a styled component's template literal to adapt it based on received props.

We pass attribute to NavLink component (lets call it green) and we can now use it in NavLink through props:

// Menu.js



<NavLink green href="/">About</NavLink>


Enter fullscreen mode Exit fullscreen mode

// Menu.styles.js



export const NavLink = styled.a`
  color: #8f5c2c;
  text-decoration: none;
  width: 100%;
  box-sizing: border-box;
  display: block;
  padding: 0.5rem;

${props => props.green &&`
    background: green;
    color: white;
  `}`


Enter fullscreen mode Exit fullscreen mode

Now it is styled differently. And this is amazing! :) But this is not all what we can do with props.

Changing Style of Specific Property based on Props

What if we want to change a style of just one single property for a specific component? We can do that also with using props.

For now both Menu button and navigation links are showing on our page, but this is not what we want exactly. We want to see navigation links ONLY when we click a button. How we can do that?

We can change display property of a MenuNavigation by passing needed behaviour (in our case, a string) through display attribute:

// Menu.js



<MenuNavigation display={"none"} />


Enter fullscreen mode Exit fullscreen mode

//Menu.styles.js



export const MenuNavigation = styled.div`
  position: fixed;
  width: 200px;
  max-width: 70%;
  height: 100%;
  left: 0;
  margin-top: 1.4rem;
  z-index: 200;
  background-color: white;
  padding: 1rem 2rem;
  transition: all 0.7s ease;
  box-shadow: 0px 8px 30px rgba(0, 0, 0, 0.2);
  display:${props => props.display}
`;


Enter fullscreen mode Exit fullscreen mode

Now we don't see navigation links anymore. But this is also not the behaviour we wanted. We want to change display dynamically: when we click MenuButton, we want to see navigation links, when we click button again, we want them to collapse again. Let's implement that!

## Changing Style of Specific Property based on Props Dynamically

To implement the above behaviour, we need to pass either true or false to the display attribute and based on that the display property will be changed either to block or none.
To do that, first we need to create a state:

//Menu.js



import { useState } from "react";
const [display, setDisplay] = useState(false);


Enter fullscreen mode Exit fullscreen mode

We initialise display variable as false, so if we use it now to set up display, we wont see anything but the button. When we click MenuButton, we change display variable to 'true' and we should see navigation links.

Let's see the code:

//Menu.js



import { useState } from "react";
import {MenuButton, Line, MenuNavigation, NavList, NavItem, NavLink} from "./Menu.styles";


export const Menu = () => {

const [display, setDisplay] = useState(false);

 // This method will change display to opposite every time we call it
const handleClick = () =>{
  setDisplay(!display);
}

  return (
    <>
      <MenuButton onClick={handleClick}>
        <Line></Line>
        <Line></Line>
        <Line></Line>
      </MenuButton>
      <MenuNavigation display={display}>
        <NavList>
          <NavItem>
            <NavLink href="/">Home</NavLink>
         </NavItem>
         <NavItem>
            <NavLink green href="/">About</NavLink>
         </NavItem>
       </NavList>
     </MenuNavigation>
    </>
  );
}



Enter fullscreen mode Exit fullscreen mode

//Menu.styles.js



export const MenuNavigation = styled.div`
  position: fixed;
  width: 200px;
  max-width: 70%;
  height: 100%;
  left: 0;
  margin-top: 1.4rem;
  z-index: 200;
  background-color: white;
  padding: 1rem 2rem;
  transition: all 0.7s ease;
  box-shadow: 0px 8px 30px rgba(0, 0, 0, 0.2);
  display:${props => props.display}
`;


Enter fullscreen mode Exit fullscreen mode

So here we receive display attribute through props to our component and we need to change display property somehow based on if we get true or false. How we can do it?

Ternary Operator with Styled Components

We can use Ternary Operator to change the style of property conditionally.
In our example, we will write the logic for display property like this:

//Menu.styles.js



export const MenuNavigation = styled.div`
  position: fixed;
  width: 200px;
  max-width: 70%;
  height: 100%;
  left: 0;
  margin-top: 1.4rem;
  z-index: 200;
  background-color: white;
  padding: 1rem 2rem;
  transition: all 0.7s ease;
  box-shadow: 0px 8px 30px rgba(0, 0, 0, 0.2);
  display:${props => props.display ? "block" : "none"}
`;


Enter fullscreen mode Exit fullscreen mode

Now it's all set up with button and navigation as we wanted. But we still have adjustments we would like to make. For example, set some media-queries, so we can only see hamburger menu on a small screen. Or we would like to add some styles for hover and active pseudo-classes for links or button right? or may be we want to add a className attribute to our component and use it instead? We can do all of these.....but in my next blog post!

So stay tuned and may be you would like Styled Components as much as i do :)

P.S. You can find the link to the project HERE if you need it.

Thank you for reading my blog. Feel free to connect on LinkedIn or Twitter :)

Buy Me a Coffee at ko-fi.com

Top comments (20)

Collapse
 
orkhanjafarovr profile image
Orkhan Jafarov

Nice explanation!
I'll add, in the new version of styled-components it possible to handle error when React throwing an error when you use unsupported/uncommon attributes for elements. styled-components.com/docs/api#tra...

Let's say:

<MenuNavigation opened  />
// Warning: unknown props 'opened' and bla bla
Enter fullscreen mode Exit fullscreen mode

To handle it you can use $ symbol

<MenuNavigation $opened  />

const MenuNavigation = styled.div`
  display: ${props => props.$opened ? 'block' : 'none'};
`;
Enter fullscreen mode Exit fullscreen mode
Collapse
 
lucassperez profile image
Lucas Perez • Edited

Nice article! Styled components are very cool, indeed.
What do you think about defining your styled components inside the same file as your normal component? This way you could potentially have a single file component, something that Vuers seem to love.
I haven't thought much about this much, just asking for some opinion.

Collapse
 
olenadrugalya profile image
Olena Drugalya

Yes, you can surely do that. But itā€™s always good to devide logic from styling in my opinion. And sometimes a component can have only styles (like a wrapper), so it is not necessary to create separate file for that. Like you can have Menu.js and Menu.styles.js which include MenuWrapper and MenuContainer

Collapse
 
sandeep18072002 profile image
Sandeep18072002

Can you help why it is resulting in 10 ;

var i = 4;

for(var i = 0 ; i<10;i++){ // using var i for block scoping
console.log(i)
}

console.log(i) // consoling global 'i' but instead of 4 result get to +1 for the for
loop conditional { 10 };

why is it so ?? Please clear my doubt.... šŸ¤”

Collapse
 
olenadrugalya profile image
Olena Drugalya

its because you re-defined var i in your loop again, so the loop uses var i = 0. If you want var i to start from 4, you should do the following:
for(var i = 4 ; i<10;i++)
OR
for(var i = i ; i<10;i++)

Collapse
 
sandeep18072002 profile image
Sandeep18072002

Bro I don't want to start my var from 4 I am saying that if-

var i = 4; // stored in globals

for(var i = 0; i<10; i++){
console.log(i); // the var is block scoped and and it's 0 it will iterate until i<10 which is just obvious but after the loop / The second console.log(i) ; refers to globals but it gives 10 ; instead of 4 or 9+4 = 13 ;; CONCERN is - why 10 [from where is became 10]
}
console.log(i); // 10 ??????????

Thread Thread
 
sivaprasadraj profile image
Siva Prasad

var doesn't create a block scope for the loop, it just rewrites the value for the variable i. Since the value of i changes to 10 after the loop ends, that will be printed. If you want to create a block scope for the loop, use let.

Collapse
 
aiosifelisl1 profile image
Andreas Iosifelis

Nice article. I love styled-components.

Collapse
 
olenadrugalya profile image
Olena Drugalya

Thank you! me too :)

Collapse
 
michelledev3 profile image
michelledev

Thanks Olena!

Collapse
 
doabledanny profile image
Danny Adams

Great article Olena, I used styled components for my blog so this was a nice reminder of what I can do with it!

Collapse
 
olenadrugalya profile image
Olena Drugalya

Thank you Danny :)

Collapse
 
ash_bergs profile image
Ash

Nice! Really cool seeing some styled components in action. I don't use them often enough šŸ¤”

Collapse
 
olenadrugalya profile image
Olena Drugalya

I wasn't either :) but than I decided to give a try and it impressed me how much you can actually do there

Collapse
 
devenock profile image
Enock Omondi

Well discussed.

Collapse
 
ryhor_b_e7d7dbae11ceaa341 profile image
Ryhor B

it is possible to create a constant inside style file and use props in that constant?

Collapse
 
palaklive profile image
palaklive

I enjoy your blog and exploring the corner of styled component.

Thank you and keep these good articles coming.

Collapse
 
olenadrugalya profile image
Olena Drugalya

Most welcome :) Iā€™m working on the next article because there is more you can do with styled components