Moshe
Moshe

Reputation: 6991

Multiple Props Options for Styled Components

I have a navbar component that I have created using Styled Components. I would like to create some props that change the background-color and/or text color.

For instance: <Navbar dark> should have the following CSS:

background: #454545;
color: #fafafa;

Whereas <Navbar light> should be the opposite:

background: #fafafa;
color: #454545;

If, however, neither prop is used, then I want to have a default background and text color -- say (for demo purposes), something like this:

background: #eee;
color: #333;

Now, my question is how to set this up in Styled Components.

I can do the following:

background: ${props => props.dark ? #454545 : '#eee'}
background: ${props => props.dark ? #fafafa : '#eee'}
background:  #eee;

And something similar for color.

But this is redundant and not very elegant. I would like some sort of if/else statement:

background: ${ props => { 
  if (props.dark) { #454545 }
  elseif (props.light) { #fafafa }
  else { #eee }
}

But I don't know how to set something like that up in Styled Components.

Any suggestions?

Thanks in advance.

Upvotes: 16

Views: 38595

Answers (7)

returnvoid
returnvoid

Reputation: 434

What about:

const StyledButton = styled.button`
    padding: 8px 16px;
    border-radius: ${props => props.rounded ? '10px' : '0px'};
    ${props => {
        switch (props.type) {
            case 'primary':
                return `
                    background-color : #000;
                    color: #fff;
                    border: 1px solid #000000;
                `;
            case 'secondary':
                return `
                    background-color : #DEDEDE;
                    border: 1px solid #999;
                `;
        }
    }
}`;

Upvotes: 1

Pax Vobiscum
Pax Vobiscum

Reputation: 2639

Solution using Styled-tools

In your specific case

Since you only got two themes, a default which is light, and a dark one you can switch to, you only really need to check if it is darkmode or not.

import {ifProp} from "styled-tools";

export const Navbar = styled.nav`
  ${ifProp("dark",
    css`
      background: ${colors.dark};
      color: ${colors.light};
    `,
    css`
      background: ${colors.light};
      color: ${colors.dark};
    `,

  )}
`;

and render with <Navbar $dark={isDarkMode} />

More general solution

Granted you still want to use a themed approach with dark/light etc. setting up variants would make things easier. For example you can keep track of the different themes you want in a separate enum. Like this:

enum Themes {
    DARK = "dark",
    LIGHT = "light",
}

In your styling later you could specify:

import {switchProp} from "styled-tools";

export const Navbar = styled.nav`
  ${switchProp({
    dark: css`
      background: ${colors.dark};
      color: ${colors.light};
    `,
    light: css`
      background: ${colors.light};
      color: ${colors.dark};
    `,

  })}
`;

and then rendering either <Navbar variant={Theme.LIGHT} /> or <Navbar variant={Theme.DARK} />

References

Upvotes: 0

Matt Carlotta
Matt Carlotta

Reputation: 19762

Keep the passed in prop name the same. Then you can utilize a switch/case statement. For example, passing in a color prop and using it as a type to be matched against a case.

Working example:

Edit Simple Styled Components


For example:

<Button color="primary">Example</Button>

components/Button

import styled from "styled-components";

const handleColorType = color => {
  switch (color) {
    case "primary":
      return "#03a9f3";
    case "danger":
      return "#f56342";
    default:
      return "#fff";
  }
};

const Button = styled.button`
  display: block;
  cursor: pointer;
  border: 0;
  margin: 5px 0;
  background: #000;
  font-size: 20px;
  color: ${({ color }) => handleColorType(color)};

  &:focus {
    outline: 0;
  }
`;

export default Button;

If you have multiple attributes (like a color and a background pair), then utilizing the same concept as above, alter the handleColorType to return a string with attributes and invoke the handleColorType function without a style property.

For example:

<MultiButton color="primary">Example</MultiButton>

components/MultiButton

import styled from "styled-components";

const handleColorType = color => {
  switch (color) {
    case "primary":
      return "color: #03a9f3; background: #000;";
    case "danger":
      return "color: #fff; background: #f56342;";
    default:
      return "color: #000; background: #eee;";
  }
};

const MultiButton = styled.button`
  display: block;
  margin: 5px 0;
  cursor: pointer;
  border: 0;
  font-size: 20px;
  ${({ color }) => handleColorType(color)};

  &:focus {
    outline: 0;
  }
`;

export default MultiButton;

Upvotes: 57

akshay sehgal
akshay sehgal

Reputation: 88

Styled components also accepts a function where in you can read props. Moreover if you choose to pass a theme prop instead, you can also define an object for your themes.


const themes = {
  dark: css `
     background: ${colors.dark};
     color: ${colors.light};
  `,
  light: css`
     background: ${colors.light};
     color: ${colors.dark};
  `
}
export const Navbar = styled.nav(({theme})=>`
  width: 100%;
  background: ${colors.light};
  color: ${colors.dark};
  ... // rest of the css

  ${theme?themes[theme]:''}

  `)

<Navbar theme="dark" />

Upvotes: 1

Mel Macaluso
Mel Macaluso

Reputation: 3760

Something more elegant (I guess) and modern would be a combination of destructuring the props and using the switch statement such as:

const Button = styled.button`
  ${({primary, secondary}) => {
      switch(true) {
        case primary:
          return `background-color : green`
        case secondary:
          return `background-color : red`
      }
    }
  }
`

Upvotes: 2

user7637140
user7637140

Reputation:

you can also do something like this:


 const colorType= {
   dark: '#454545',
   light: '#0a0a0a',
   normal: '#dedede'
};



export const Navbar= styled.nav`
   background: ${({color}) => colorType[color] || `${color}`};

`;

and Here you are :

<Navbar color="primary" />
<Navbar color="#FFFFFF" />

Upvotes: 0

Moshe
Moshe

Reputation: 6991

This is the solution I ended up using:

export const Navbar = styled.nav`
  width: 100%;

  ...  // rest of the regular CSS code

  ${props => {
    if (props.dark) {
      return `
        background: ${colors.dark};
        color: ${colors.light};
    `
    } else if (props.light) {
      return `
        background: ${colors.light};
        color: ${colors.dark};
    `
    } else {
      return `
        background: ${colors.light};
        color: ${colors.dark};
    `
    }
  }}
`

Upvotes: 19

Related Questions