Styled Components: Styling for component based application

Encapsulating styles for reusability throughout our codebase

ctually CSS is easy language to learn, but it takes years to master how to write and manage your styles. CSS have come across different waves of preprocessors like LESS, SASS/SCSS, Stylus, POST CSS which ultimately compiles to CSS. But, the rise in the modern Javascript frameworks like Angular, React, Vue, Svelte have brought us together for practicing a component based user interfaces, which we call it “component age”.

This has opened the door to a new way of organizing our styles with CSS in JS. Moving quickly to adopt the CSS in JS philosophy with Styled Components. It helps in attaching CSS directly to our JS Components. When we have CSS in stylesheet file it’s separated with the components and we need to reach into the CSS with class names. But CSS never had actual modules but can be done now.

CSS-in-JS relies on JavaScript’s modules implementation.

With CSS-in-JS, we have all the power of CSS at our fingertips. Since actual CSS is generated, you can use every media query and pseudo selector you can think of. Some libraries (like jss, styled-components) even add support for neat, non-CSS-native features like nesting as well!

So, let’s now get into how we can style our component that is encapsulated into its own style. We are not styling an HTML elements based on their class names.

As styled-components co-creator Max Stoiber says:

“The basic idea of styled-components is to enforce best practices by removing the mapping between styles and components.”

Lets now create a simple React app which uses the create-react-app under the hood. Once we finish setting up our React boilerplate we will install our package styled-components from npm.

Styling with styled component follows syntax which is identical to CSS. The CSS syntax uses ES6 tagged template literals, which are generated with its unique classNames for each rules, and attach the respective class names to its unique DOM nodes of the component. The stylesheet will compile in runtime and gets injected at the end of <head> section at runtime. Now lets write our styles with styled-components.

Styled

import styled from 'styled-components'; const Box = styled.div`  
display: grid;
grid-template-columns: 100px 100px;
grid-gap: 10px;
`;
export default Box;

Here in this piece of code style is a default export of the style-component. We have created the Box component which acts as a parent container for all its child component other than Header. We have used styled.div to create a styled component that renders a div. All the DOM elements are present as methods on the styled object.

Using styled as a factory function:

const Button = ({ className }) => (<div className={className}><Button/></div>)export default styled(Button)`  
background-color: red;
color: white;
padding: 15px 10px;
border-radius: 3px;
`;

styled can also be invoked as a function (factory call) itself to wrap the existing React component. In the above code we have created the Button which is a simple stateless React component and then call the styled factory function with the Button as an argument to wrap it to its necessary styles. We need to set the component className attribute on the DOM element to this.props.className to take the effect.

Pseudo-elements, pseudo-selectors and keyframes

import React from 'react';
import styled, { keyframes } from 'styled-components';
import { getColor } from '../utils/theme'
const Loader = ({ className }) => (<div className={className}><Myloader/></div>)const loading = keyframes` 0% {
top: 28px;
left: 28px;
width: 0;
height: 0;
opacity: 1;
}
100% {
top: -1px;
left: -1px;
width: 58px;
height: 58px;
opacity: 0;
}
const Myloader = styled.div`
display: inline-block;
position: relative;
width: 64px;
height: 64px;
animation-delay: -0.5s;

&::after {
content: "";
position: absolute;
border: 4px solid #fff;
opacity: 1;
border-radius: 50%;
animation: ${loading} 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}`;

Here in this piece of code we created a simple animation Loader component using keyframes and psuedo-classes. Styled-component export a keyframes helper function as a named export that is used to create animation keyframes. The API is somewhat similar to the one of styled.tagname and the generated keyframes object is used in the animation property in style last line of psuedo classes with ${..} syntax.

About our getColor utility function which helps us to extract color values to our theme. Using the psuedo-elements the syntax is more alike in SCSS (eg: &::after), and also we need to set a empty string property alike in CSS
content: ‘’ for the pseudo-element. Similarly pseudo-selectors like :visited, :hover, :active and eve transition can also be used inside styled-components alike CSS.

Props and the css helper

import styled, { css } from 'styled-components'; 
import { getFontSize, getColor } from '../utils/theme';
const Button = styled.button `
font-size: ${getFontSize('mdFont')};
margin: 1em;
background-color: myred;
border: 2px solid ${getColor('primary')};
border-radius: 3px;
background: ${props => props.primary && 'myred'}
color: ${props => props.primary ? 'white' : 'myred'};
`;
<Button primary>My Blog</Button>
<Button>I love reactive programming !</Button>

In keeping with this no-classes philosophy, styled-components makes use of props over classes when it comes to customizing the behavior of a component. The above piece of code has a styled button component where we have added a prop object and passed it in our component HTML tags. In this way the props can customize the behavior and add customizing behavior into our styles.

CSS-in-JS helps to avoid non-deterministic source order specificity.

Extending our styles

import React from 'react';
import styled, { keyframes } from 'styled-components';
import { getColor } from '../utils/theme'
const Myfield = styled.span`
font-size: ${getFontSize('mdFont')};
color: ${getColor('myred')};
padding: 5px;
`;
const Label = Value.extend`
font-weight: bolder;
color: ${getColor('secondary')};
`;

Sometimes during our CSS writing, we may come across places where we need to change styles based on props, solely props are not just enough. Here in the piece of code we have called extend method on that component.

Media queries

const breakPoint = '768px';
export default styled(OurServices)`
padding: 15px;
display: flex;
justify-content: space-between;
background: ${getColor('secondary')};
color: ${getColor('mainColor')};

@media (max-width: ${breakPoint}) {
flex-direction: column;
justify-content: center;
align-items: center;
}`;

In the above code we have added our media queries with the screen lower than 768px, where we changed flex direction to column and other flex box properties. So, adding our endpoints is much easier.

Global styles

injectGlobal`  * {    
border: none;
margin: 0;
padding: 0;
box-sizing: border-box;
}
html, body, #root {
height: 100vh;
width: 100%;
overflow-x: hidden;
}

a, a:hover,
a:active,
a:visited {
text-decoration: none;
color: inherit;

}`;

Some styles are needed in all pages of our product, these styles stays inside index.global-styles.js files. These styles include the general styles needed in most of the project. The styled-components library provides us a helper function as named export for that too — injectGlobal can be used to add global styles using the now familiar tagged template literal syntax.

CSS-in-JS gives the developer more expressiveness while encouraging more maintainable patterns than cascading.

Theming

const rootElement = document.getElementById('root');ReactDOM.render(  
<ThemeProvider theme={theme}>
<BrowserRouter>
<App />
</BrowserRouter>
</ThemeProvider>,
rootElement,
);

In our index.js file we wrap our App component where our application lives with Theme Provider and pass theme object. This will serve as a default theme.

export const theme = {
color: {
primary: '#064acb',
secondary: '#f2f3f3',
light: '#fafafa',
},
fontSize: {
lg: '34px',
md: '23px',
sm: '16px',
xs: '12px',
}
,};
export const getFontSize = size => props => props.theme.fontSize[size];
export const getColor = color => props => props.theme.color[color];

We created a theme.js default theme object which accepts our theme fundamentals like color and font size. And later we export to use it.

import styled, { ThemeProvider } from 'styled-components';
import { theme, getColor } from './utils/theme';
class AppContainer extends Component {
state = {
users: [],
theme: true,
}};
render() {
const { users, theme } = this.state;
return(
<Template users={users} className={this.props.className}
theme={theme}
/>
);
}}
export default styled(AppContainer)`
width: 100%;
margin: 0 auto;
min-height: 100vh;
background: ${getColor('light')}
`;

Here we rendered our theme object in our App.js. It uses same object properties that we have set it in our previous file.

CSS-in-JS gives developers API to describe state-based styles in a better way than using a bunch of conditional class names.

Conclusion

I hope I was able to give you some core features that we can use in styling our component based application. I think there are many other better ways of organizing our styles in our big application. CSS in JS is also one of the evolving method of today. There are many libraries out there which can help us organize our component based application as well.

Image for post
Image for post
src: npm trends

But in my personal preference styled-components is one of the best solutions available for styling any component based application. We have only discussed the most common of the possible use cases but there is much more to the library which you can explore in their documentation. styled-components have great SSR support as well. Please feel free to give it a try in your next project.

Written by

Product Designer and Frontend Developer | https://twitter.com/ishan02016

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store