styled components folder structure

React Styled Components Folder Structure Best Practices for Scalable Application

Author Profile
Abdul Basit OnLinkedIn

Styled Components are an excellent way to write reusable and easily manageable CSS-in-JS code. If you’ve been following my posts here, you might have noticed styled components quite often. In this article, I will share how I personally like to organize styled components in Reactjs projects with Typescript so that you can use them in your web apps and personalize them according to your aesthetics.

What should be the Folder Structure of styled components?

Maintaining proper folder structure is important for a project’s scalability, as well as for your own personal convenience and organization. A poor folder structure can make management difficult. It also happens that we don’t take structuring seriously in the start while it's apparently easier to manage, but once the project starts growing and more is added to it, organization and management start to become a pain and we regret not having taken care of the basics early on.

The most common and basic “best practice” for folder structuring in Reactjs or gatsbyjs projects is creating the src folder at the root in React. For styled components, we can create a styles folder inside the src folder. All styles are then kept in the styles folder. In my case, it has four main files:

folder structure styled components

Styled Components File Structure

  1. Theme.ts
  2. Global.ts
  3. Breakpoints.ts
  4. Fonts.module.css

Let us discuss them one by one.

Note

We are using styled-components v6, which includes TypeScript types, so there's no need to install them separately.

1. Theming in Styled Components with Typescript

While working with styled-components, I noticed that theming in styled-components with TypeScript is a powerful and much easier to implement. All you need to do is to create a theme object and define all your colors, fonts, padding, margins, and other configurations there, and use theme variables wherever you need them in your app.

One great advantage of using TypeScript is that you can leverage its IntelliSense for theming. For that you will create a new file styled.d.ts and define your theme object there as well. For referece look at the Styled Components React GitHub Repo.

import { DefaultTheme } from 'styled-components'
export const theme: DefaultTheme = {
colors: {
primary: '#FAFAFA',
secondary: '#FFC80A',
tertiary: '#303030',
background: '#ffffff',
text: '#000000',
primaryTextColor: '#594F43',
secondaryTextColor: '#777777',
inputPlaceholder: '#C7C7C7',
darkGrayText: '#303030',
darkText: '#1A1A1A',
black: '#000000',
white: '#ffffff',
dark: '',
medium: '',
light: '',
danger: '',
success: '#66A15A',
},
fonts: {
anekMalayalam: 'Anek Malayalam',
},
paddings: {
container: '15px',
pageTop: '30px',
},
margins: {
pageTop: '30px',
},
}

styled.d.ts file

// import original module declarations
import 'styled-components'
// and extend them!
declare module 'styled-components' {
export interface DefaultTheme {
colors: {
primary: '#FAFAFA'
secondary: '#FFC80A'
tertiary: '#303030'
background: '#ffffff'
text: '#000000'
primaryTextColor: '#594F43'
secondaryTextColor: '#777777'
inputPlaceholder: '#C7C7C7'
darkGrayText: '#303030'
darkText: '#1A1A1A'
black: '#000000'
white: '#ffffff'
dark: ''
medium: ''
light: ''
danger: ''
success: '#66A15A'
}
fonts: {
anekMalayalam: 'Anek Malayalam'
}
paddings: {
container: '15px'
pageTop: '30px'
}
margins: {
pageTop: '30px'
}
}
}

Now, wherever we use theme variables, we will get IntelliSense code completion like this.

Isn't it awesome?

styled components theme intellisense

How to use theme in styled components

Import ThemeProvider from styled-components that takes a props theme. Now, get all the theme properties to the components wrapped inside ThemeProvider.

import styled, { ThemeProvider } from 'styled-components'
import { GlobalStyles } from './styles/Global'
import { theme } from './styles/Theme'
const Title = styled.h1`
color: ${(props) => props.theme.colors.primaryTextColor};
`
function App() {
return (
<ThemeProvider theme={theme}>
<GlobalStyles />
<Title>Hello World!</Title>
</ThemeProvider>
)
}
export default App

2. Global.ts | Global Styles in Styled Components

In global styles, we reset all the default styling.

You may have noticed I have defined font-family, color (font/text color), and background-color in body, so it impacts the whole application.

import styled, { createGlobalStyle, css } from 'styled-components'
import fontsCss from './fonts.module.css'
export const GlobalStyles = createGlobalStyle`
${fontsCss} // this works as a normal styled css
/* Box sizing rules */
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
font-size: 100%;
}
body {
margin: 0;
padding: 0;
overflow-x: hidden;
min-height: 100vh;
text-rendering: optimizeSpeed;
font-family: ${({ theme }) => theme.fonts.anekMalayalam}, sans-serif;
font-size: 1rem;
color: ${({ theme }) => theme.colors.text};
background-color: ${({ theme }) => theme.colors.background};
line-height: 1;
}
h1,
h2,
h3,
h4,
h5,
h6,
p,
ul,
figure,
blockquote,
dl,
dd {
padding: 0;
margin: 0;
}
button {
border: none;
background-color: transparent;
font-family: inherit;
padding: 0;
cursor: pointer;
}
/* Remove list styles on ul, ol elements with a list role, which suggests default styling will be removed */
ul[role="list"],
ol[role="list"] {
list-style: none;
}
li {
list-style-type: none;
}
/* Set core root defaults */
html:focus-within {
scroll-behavior: smooth;
}
/* A elements that don't have a class get default styles */
a:not([class]) {
text-decoration-skip-ink: auto;
}
/* Make images easier to work with */
img,
picture {
max-width: 100%;
display: block;
}
/* Inherit fonts for inputs and buttons */
input,
button,
textarea,
select {
font: inherit;
}
/* Remove all animations, transitions and smooth scroll for people that prefer not to see them */
@media (prefers-reduced-motion: reduce) {
html:focus-within {
scroll-behavior: auto;
}
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
`

3. Breakpoints in Styled Components

Breakpoints are the points at which the website content adjusts to the device width, allowing you to present the best possible layout to the user. In the given code, I have used max-width if you like you can change it to min-width and play with breakpoints values as per your need.

interface Size {
xs: string
sm: string
md: string
lg: string
xl: string
xxl: string
}
const size: Size = {
xs: '400px', // for small screen mobile
sm: '600px', // for mobile screen
md: '900px', // for tablets
lg: '1280px', // for laptops
xl: '1440px', // for desktop / monitors
xxl: '1920px', // for big screens
}
export const device = {
xs: `(max-width: ${size.xs})`,
sm: `(max-width: ${size.sm})`,
md: `(max-width: ${size.md})`,
lg: `(max-width: ${size.lg})`,
xl: `(max-width: ${size.xl})`,
xxl: `(max-width: ${size.xxl})`,
}

How to use breakpoint in media queries in styled components

To use break point in styled component we have imported the device object from BreakPoints file, and after that use the required size.

import styled, { ThemeProvider } from 'styled-components'
import { device } from './styles/BreakPoints'
import { theme } from './styles/Theme'
const Title = styled.h1`
color: ${(props) => props.theme.colors.primaryTextColor};
font-size: 48px;
@media ${device.md} {
font-size: 32px;
}
`
function App() {
return (
<ThemeProvider theme={theme}>
<Title>Hello world</Title>
</ThemeProvider>
)
}
export default App

I learned this technique from Mario Kandut this article

Read the article how to use media queries in styled components to learn more about media queries and breakpoints.

4. Using woff2 and Woff font in Styled Components

I have downloaded fonts in woff2 and woff format, the lighter and recommended font format to use, and added them to assets/fonts folder.

woff format fonts styled components
/* woff2 : Super Modern Browsers */
/* woff :Modern Browsers */
@font-face {
font-family: 'Anek Malayalam';
font-style: normal;
font-weight: 100;
src: url('../assets/fonts/anek-malayalam-v4-malayalam-100.woff2') format('woff2'), url('../assets/fonts/anek-malayalam-v4-malayalam-100.woff')
format('woff');
font-display: swap;
}
@font-face {
font-family: 'Anek Malayalam';
font-style: normal;
font-weight: 200;
src: url('../assets/fonts/anek-malayalam-v4-malayalam-200.woff2') format('woff2'), url('../assets/fonts/anek-malayalam-v4-malayalam-200.woff')
format('woff');
font-display: swap;
}
@font-face {
font-family: 'Anek Malayalam';
font-style: normal;
font-weight: 300;
src: url('../assets/fonts/anek-malayalam-v4-malayalam-300.woff2') format('woff2'), url('../assets/fonts/anek-malayalam-v4-malayalam-300.woff')
format('woff');
font-display: swap;
}
@font-face {
font-family: 'Anek Malayalam';
font-style: normal;
font-weight: 400;
src: url('../assets/fonts/anek-malayalam-v4-malayalam-400.woff2') format('woff2'), url('../assets/fonts/anek-malayalam-v4-malayalam-400.woff')
format('woff');
font-display: swap;
}
@font-face {
font-family: 'Anek Malayalam';
font-style: normal;
font-weight: 500;
src: url('../assets/fonts/anek-malayalam-v4-malayalam-500.woff2') format('woff2'), url('../assets/fonts/anek-malayalam-v4-malayalam-500.woff')
format('woff');
font-display: swap;
}
@font-face {
font-family: 'Anek Malayalam';
font-style: normal;
font-weight: 600;
src: url('../assets/fonts/anek-malayalam-v4-malayalam-600.woff2') format('woff2'), url('../assets/fonts/anek-malayalam-v4-malayalam-600.woff')
format('woff');
font-display: swap;
}
@font-face {
font-family: 'Anek Malayalam';
font-style: normal;
font-weight: 700;
src: url('../assets/fonts/anek-malayalam-v4-malayalam-700.woff2') format('woff2'), url('../assets/fonts/anek-malayalam-v4-malayalam-700.woff')
format('woff');
font-display: swap;
}
@font-face {
font-family: 'Anek Malayalam';
font-style: normal;
font-weight: 800;
src: url('../assets/fonts/anek-malayalam-v4-malayalam-800.woff2') format('woff2'), url('../assets/fonts/anek-malayalam-v4-malayalam-800.woff')
format('woff');
font-display: swap;
}

Note

JS file for fonts was reloading on every activity on the screen. We used a CSS file for fonts to fix this issue.

Testing Fonts in Styled Components

It’s time to test the fonts to see if we have it all set up correctly. For that, I have tested fonts from font-weight: 100 to font-weight: 800 in App.js.

Besides I used WhatFont google chrome extension to verify it.

testing font with what font

Top UI Components Built with React and Styled Components

UI Components Built with React and Styled Components

Here are the top 5 widely-used React components crafted using TypeScript and Styled Components:

  1. Navbar
  2. Button
  3. Input
  4. Radio Button
  5. Progress Steps

I will add more UI components in this React Styled Components Repo time to time. So don't forget to star it if this repo helps you in any way.😉

And that’s it, guys. We looked at folder structuring in the context of styled components, as well as the files that are part of the styles folder. Hope it added to your knowledge.

You can access these codes from this GitHub Repository