Styled components - conditional styles with TypeScript

Sunscrapers Team

27 July 2022, 6 min read

thumbnail post

Intro

There is a popular library called styled-components it is also one of the ways to write styles in modern SPA applications in React. One of the biggest pros is that you can write actual JS logic inside of them, so your styles can be changed based on the props you pass down to them. This allows you to write less duplicated code.

Another big thing is that styled components have an isolated scope, meaning the style you wrote for your components won’t affect other components unless you want to.

It also means you can re-use the components without worrying that it would break styles across your whole application. The library supports code-splitting, automatic vendor prefixing, and simple dynamic styling.

That’s why this library is also quite popular with React Native projects.

styled-components are also quite an easy way to customize components you have available in the most popular UI frameworks that React developers use, such as Material-UI (MUI) and others.

Setup

Inside your project directory - run the following command:

# with npm
npm install --save styled-components
# with yarn
yarn add styled-components

How to start

In the first step make an import:

import styled from 'styled-components';

Optionally, you can assign types or interfaces:

type PhotoWrapperProps = {
  readonly picture: string;
  readonly position: string;
  readonly bckheight: string; 
  readonly children?: JSX.Element; 
};

In the next step write your component structure.

PhotoWrapper is our styled wrapper which is receiving props - so they can be used to introduce some parameterization or ”easy customization” of components, meaning you can change single CSS properties based on actual React props passed to the component.

export const HeaderWithPhoto = ({
  picture,
  bckheight,
  position,
  children,
}: PhotoWrapperProps) => { 
  return (
  <PhotoWrapper
     picture={picture}
     position={position}
     bckheight={bckheight}
  >
  {children} 
  </PhotoWrapper> 
 );
}; 

Rules

  1. If you want to style html element - use dotted notation as shown in example:
const MyWrapper = styled.div` 
  background: red;
`;
  1. If you want to styled some existing component - add and import at the top and use brackets:
const ButtonWrapper = styled(Button)`
  background: red; 
`;

//and then use ButtonWrapper instead of Button inside your components, it will work just the same, but will also have additional styles
  1. You can also pass types or interfaces using square brackets []:
// import styled, { StyleSheetManager } from 'styled-components'
// import stylisRTLPlugin from 'stylis-plugin-rtl';

const Box = styled.div`
  background: mediumseagreen;
  border-left: 10px solid red;
`;

render(
  <StyleSheetManager stylisPlugins={[stylisRTLPlugin]}>
    <Box>My border is now on the right!</Box>
  </StyleSheetManager>
);
  1. You can also pass props:

We are using string interpolation syntax since the styled component is wrapped with backticks.

There are two ways of assigning props inside styled-components:

  • using props object:
`background: ${props => props.backgroundPicture };`
  • using destructuring:
`background: ${({ backgroundPicture }) => backgroundPicture };`
const PhotoBackgroundWrapper = styled.div<HeaderWithPhotoBackgroundProps>` 
  background: rgba(0, 0, 0, 0.5); 
  background: ${({ picture }) => 
  `linear-gradient(rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('${picture}') no-repeat 
`}; 
min-height: ${props => props.bckheight}; 
background-position: ${props => props.position}; 
`; 

Using

  1. If-else logic inside styled-components:

Using if-else logic inside styled-components helps to reduce boilerplate code and duplication.

Before styled-components you had to change the className attribute based on some property value:

<>   
  {someBooleanValue   
    ? <div className="style-1`">content</div>
    : <div className="style-2">content</div> 
  }
</>   

or if you had more props then probably something like this - and create a lot of css classes and nested if statements:

{someBooleanValue 
    ? <div className=`style-1 red-border ${classNameDependsOnCondtion}`>content</div>
    : <div className="style-2 blue-border">content</div>
}   

Also you got a lot of boilerplate - divs/spans with classes.

It obscures code readability if you had a lot of these conditions.

In the styled component case you wrap the component you want to style and give it a name like StyledSidebar and can use it instead of a component from some UI library.

Another thing is, that with class based components, css code is not encapsulated, so nested components can affect other components styles. With styled components - it generates unique class names for your styles/components.

That’s why the styled-components library is quite popular with React-Native developers.

  1. Ternary operator:
const Box = styled.div`
  height: ${props => props.size === 'small' ? '20px' : '40px'}
  width: ${props => props.size === 'small' ? '20px' : '40px'} 
`;
  1. Logical operators:
const Box = styled.div`
// last value after || operator is default option

  height: ${({size}) =>
  size === 'small' && '25px' ||
  size === 'large' && '100px' ||  
  '50px'
  };
  width: ${({size}) => size === 'small' && '25px' ||  
  size === 'large' && '100px' ||
  '50px'
  }';
// Render.  
<Box/>// 50px - Normal.
<Box size="small"/>// 25px - Small.
<Box size="large"/>// 100px - Large.

or using css helper method from styled-components

const Box = styled.div`
  height:100px; 
  width:100px;
  ${props => props.size === 'small' && css`
    height:20px; 
    width:20px;
  `}
`; 

But what if you want to change the behavior of one component based on the style of the other component?

This one is pretty tricky, but we can use example which is being referred to in styled-components documentation:

const Link = styled.a` 
  display: flex;
  align-items: center;   
  padding: 5px 10px;   
  background: papayawhip;    
  color: palevioletred;   
`;

const Icon = styled.svg`
  flex: none;
  transition: fill 0.25s;
  width: 48px;
  height: 48px;   

  // you can use reference to other styled components this way
  // as styled-components use string interpolation mechanism ⬇
  
  ${Link}:hover & {   
    fill: rebeccapurple;   
  }    
`;    

Summary

Styled-components is a really powerful library, even in cases you decide to go with some UI framework. It can help you write and style your own controls in a really efficient way.

Also, there is a “spinoff” library - called Emotion which uses some parts of the styled-components API.

More resources

Are you ready for your next project?

Whether you need a full product, consulting, tech investment or an extended team, our experts will help you find the best solutions.

Hi there, we use cookies to provide you with an amazing experience on our site. If you continue without changing the settings, we’ll assume that you’re happy to receive all cookies on Sunscrapers website. You can change your cookie settings at any time.