Styled Components in React: An In-Depth Guide
This chapter will explore Styled Components, a popular library for styling React applications. Styled Components allows developers to write CSS directly within their JavaScript code in an elegant and reusable manner. While various approaches exist for styling React components, Styled Components offers a unique method focused on component encapsulation and maintainability.
Introduction to Styled Components
Styled Components provides a way to write CSS in JavaScript (often referred to as CSS-in-JS). This approach offers several benefits, including component-level styling and improved code organization.
CSS-in-JS: A technique of writing CSS styles within JavaScript files, often associated with component-based frameworks like React. It allows for component-scoped styling and dynamic styling capabilities.
While some developers may prefer traditional CSS stylesheets, Styled Components presents a compelling alternative, particularly for projects emphasizing component-based architecture.
Why Consider Styled Components?
There isn’t a single “correct” way to style React applications. The choice often comes down to personal or team preference and project requirements. While global stylesheets are perfectly valid, Styled Components excels in scenarios where:
- Component Encapsulation is Key: Styled Components promotes a style encapsulation approach, where styles are directly associated with the components they style. This reduces the risk of style conflicts and enhances component reusability.
- Maintainability and Organization are Prioritized: By co-locating styles with components, Styled Components improves code organization and makes it easier to maintain styles as the application grows.
- Dynamic Styling is Frequently Used: Styled Components simplifies dynamic styling based on component props or application state.
Styled Components is widely adopted within the React ecosystem. Understanding it is beneficial, as you are likely to encounter it in various projects.
Course Structure
This chapter is structured in two parts:
-
Fundamentals (First Section): We will begin by covering the fundamental concepts of Styled Components, including:
- Creating Styled Components
- Nesting Styles
- Using Props for Dynamic Styling
- Implementing Themes for Consistent Styling
- Applying Global Styles
-
Project-Based Learning (Subsequent Sections): After establishing a solid understanding of the fundamentals, we will apply our knowledge by building a practical project: a landing page inspired by the “Huddle landing page” challenge from Front-End Mentor. This project will allow us to utilize the concepts learned, including props, media queries, and more.
Let’s begin by setting up our development environment and exploring the basics of Styled Components.
Setting Up and Fundamentals
To start, we assume you have a basic React application set up, ideally using Create React App. If you don’t, you can quickly create one using the following command in your terminal:
npx create-react-app styled-components-demo
cd styled-components-demo
npm start
This will create a new React application and start the development server.
Installation
First, we need to install the styled-components
library. Open a new terminal window, navigate to your project directory, and run the following command using npm or yarn:
npm install styled-components
or
yarn add styled-components
This command will add Styled Components as a dependency to your project.
Cleaning Up the Default React App
After installation, let’s clean up the default React app to start with a clean slate.
-
Delete Unnecessary Files: Navigate to the
src
folder and delete:logo.svg
(if present)App.css
index.css
-
Update
index.js
: Openindex.js
and remove the line that importsindex.css
:// Remove this line: // import './index.css';
-
Update
App.js
: OpenApp.js
and:- Remove the import statements for
logo.svg
,App.css
, andindex.css
. - Clear the content within the main
div
in thereturn
statement and replace it with a simple<h1>Hello World</h1>
.
import React from 'react'; // Remove these lines: // import logo from './logo.svg'; // import './App.css'; function App() { return ( <div> <h1>Hello World</h1> </div> ); } export default App;
- Remove the import statements for
With these steps, you have a basic, unstyled React application ready for integrating Styled Components.
Creating Your First Styled Component
In traditional React styling, you might add classes (using className
in JSX) to HTML elements and then define those classes in separate CSS files. However, Styled Components allows us to create styled components directly in our JavaScript files.
Let’s create a Container
component that centers content on the page and sets a specific width.
-
Create a
styles
folder: Inside thesrc
folder, create a new folder namedstyles
. -
Create
Container.styled.js
: Inside thestyles
folder, create a new file namedContainer.styled.js
. The.styled.js
naming convention is a common practice to distinguish Styled Component files. -
Define the Styled
Container
: OpenContainer.styled.js
and add the following code:import styled from 'styled-components'; export const Container = styled.div` max-width: 1000px; padding-left: 20px; padding-right: 20px; margin: 0 auto; `;
Let’s break down this code:
import styled from 'styled-components';
: This line imports thestyled
object from thestyled-components
library. This object is the primary tool for creating styled components.export const Container = styled.div``...``;
: This line creates and exports a styled component namedContainer
.styled.div
: This indicates that we are creating a styleddiv
element. You can use other HTML tags likestyled.span
,styled.header
,styled.button
, etc., to style different HTML elements.`...`
: These are backticks, which are used to define a tagged template literal in JavaScript. Within these backticks, you write standard CSS syntax.
-
Import and Use
Container
inApp.js
: OpenApp.js
and modify it as follows:import React from 'react'; import { Container } from './styles/Container.styled'; // Import the Container component function App() { return ( <Container> {/* Use the Container component */} <h1>Hello World</h1> </Container> ); } export default App;
import { Container } from './styles/Container.styled';
: This line imports theContainer
styled component we just created. Note the curly braces{}
because it’s not a default export.<Container>
and</Container>
: We wrap our<h1>Hello World</h1>
element with theContainer
component. This applies the styles defined inContainer.styled.js
to the content within it.
Now, if you run your React application, you should see “Hello World” centered on the page with padding on the left and right, due to the styles applied by the Container
component.
Understanding Tagged Template Literals
Styled Components utilizes JavaScript’s tagged template literals.
Tagged Template Literal: A more advanced form of template literals in JavaScript that allows functions to have control over how template literals are interpreted. In Styled Components, the
styled.div
(or other HTML tag) acts as the “tag” function, processing the CSS within the backticks.
The CSS written inside the backticks is not just a regular string. Styled Components parses this CSS, and when the Container
component (in our example) is rendered, it dynamically generates unique class names and injects the corresponding CSS into the document’s <head>
section. This ensures that the styles are scoped to the Container
component and don’t interfere with other parts of the application.
Creating a Header Component with Styled Components
Let’s create a more complex component, a Header
, and apply styles using Styled Components.
-
Create
Header.js
: Inside thesrc/components
folder (create this folder if it doesn’t exist), create a new file namedHeader.js
. This will be our regular React component. -
Create
Header.styled.js
: Inside thesrc/styles
folder, create a new file namedHeader.styled.js
. This will contain the Styled Components for ourHeader
. -
Define Styled Components in
Header.styled.js
: OpenHeader.styled.js
and add the following code:import styled from 'styled-components'; export const StyledHeader = styled.header` background-color: #ebfbff; padding: 40px 0; `; export const StyledNav = styled.nav` display: flex; align-items: center; justify-content: space-between; margin-bottom: 40px; @media (max-width: ${({ theme }) => theme.mobile}) { flex-direction: column; align-items: center; } `; export const StyledLogo = styled.img` @media (max-width: ${({ theme }) => theme.mobile}) { margin-bottom: 40px; } `;
Here, we’ve created three styled components:
-
StyledHeader
: Styles the<header>
HTML5 tag with a background color and padding. -
StyledNav
: Styles the<nav>
tag to create a navigation bar using flexbox, with responsiveness for smaller screens using a media query. -
StyledLogo
: Styles<img>
tag for logo, adding margin-bottom in mobile view using media query.
Media Query: A CSS technique that allows applying different styles based on the characteristics of the device or browser, most commonly the viewport width. In Styled Components, media queries are written directly within the CSS template literal, often leveraging template literals for dynamic values.
@media (max-width: ${({ theme }) => theme.mobile})
: This is a media query targeting screens with a maximum width defined bytheme.mobile
(we will define themes later).
-
-
Create
Header
React Component inHeader.js
: OpenHeader.js
and add the following code:import React from 'react'; import { StyledHeader, StyledNav, StyledLogo } from '../styles/Header.styled'; // Import styled components import { Container } from '../styles/Container.styled'; // Import Container component function Header() { return ( <StyledHeader> <Container> <StyledNav> <StyledLogo src="./images/logo.svg" alt="" /> <button>Try It Free</button> </StyledNav> {/* ... rest of header content will be added later ... */} </Container> </StyledHeader> ); } export default Header;
- We import the styled components
StyledHeader
,StyledNav
, andStyledLogo
fromHeader.styled.js
, and theContainer
component. - We use these styled components instead of regular HTML tags in our JSX structure.
- We import the styled components
-
Update
App.js
to includeHeader
: OpenApp.js
and update it to include theHeader
component:import React, { Fragment } from 'react'; // Import Fragment import Header from './components/Header'; // Import Header component import { Container } from './styles/Container.styled'; function App() { return ( <Fragment> {/* Use Fragment to wrap multiple components */} <Header /> <Container> <h1>Hello World</h1> </Container> </Fragment> ); } export default App;
- We import
Fragment
from React to wrap multiple components in thereturn
statement without adding an extra DOM element. - We import and render the
Header
component above theContainer
.
- We import
Now, your application should display a styled header with a navigation bar containing a logo (you’ll need to place logo.svg
in the public/images
folder - you can get it from the mentioned GitHub repository or use any SVG logo for testing) and a “Try It Free” button.
Nesting Styles
Styled Components allows you to nest CSS selectors, similar to CSS pre-processors like Sass or Less. This improves the organization and readability of your styles, especially for complex components.
In Header.styled.js
, within the StyledHeader
definition, we can add styles for the h1
element that might be present inside the header:
export const StyledHeader = styled.header`
background-color: #ebfbff;
padding: 40px 0;
h1 { /* Nested style for h1 within StyledHeader */
color: red;
}
&:hover { /* Nesting for pseudo-selector :hover for StyledHeader itself */
background-color: black; /* Example, not to be kept for header */
color: white; /* Example, not to be kept for header */
}
`;
h1 { ... }
: Styles anyh1
element that is a direct or indirect child of theStyledHeader
component.&:hover { ... }
: Uses the ampersand&
to refer to theStyledHeader
component itself, allowing you to style pseudo-selectors like:hover
,:active
,:focus
, etc.
CSS Pre-processor: A tool that extends the capabilities of standard CSS by adding features like variables, nesting, mixins, and functions. Sass and Less are popular examples. Styled Components’ nesting feature provides a similar organizational benefit within JavaScript.
Note: While nesting is available, it’s important to use it judiciously to maintain clarity and avoid overly complex selectors. Over-nesting can sometimes make styles harder to understand and maintain.
Using Props for Dynamic Styling
One of the powerful features of Styled Components is the ability to dynamically style components based on props passed to them.
Let’s modify the StyledHeader
to accept a bg
prop to change its background color dynamically.
-
Modify
StyledHeader
inHeader.styled.js
:export const StyledHeader = styled.header` background-color: ${(props) => props.bg || '#ebfbff'}; /* Dynamic background color from props */ padding: 40px 0; `;
background-color: ${(props) => props.bg || '#ebfbff'};
: This line sets thebackground-color
style dynamically.${(props) => props.bg || '#ebfbff'}
: This is a JavaScript arrow function within the CSS template literal. It receives theprops
object as an argument.props.bg
: Accesses thebg
prop passed to theStyledHeader
component.|| '#ebfbff'
: If thebg
prop is not provided (or is falsy), it defaults to#ebfbff
(the original light blue color).
-
Pass the
bg
prop inApp.js
(orHeader.js
):In
App.js
(or within theHeader
component if you want to set it there), you can now pass thebg
prop to theHeader
component:// In App.js <Header bg="red" />; // Example: set background to red <Header />; // Example: use default background color
Or within
Header.js
:// In Header.js <StyledHeader bg="lightgreen"> {/* Example: set background to light green */} {/* ... header content ... */} </StyledHeader> <StyledHeader> {/* Example: use default background color */} {/* ... header content ... */} </StyledHeader>
Now, if you pass the bg
prop, the header’s background color will change accordingly. If you don’t pass the bg
prop, it will use the default light blue color.
Themes for Consistent Styling
Themes in Styled Components provide a centralized way to manage and share styling values across your application, such as colors, fonts, breakpoints, and spacing units. This promotes consistency and makes it easier to update your application’s visual style.
-
Create a Theme Object in
App.js
:In
App.js
, before theApp
component function, define atheme
object:const theme = { colors: { header: '#ebfbff', body: '#fff', footer: '#003333', }, mobile: '768px', // Example mobile breakpoint };
This
theme
object contains:colors
: An object holding color values for different parts of the application (header, body, footer).mobile
: A breakpoint value for mobile devices.
-
Use
ThemeProvider
to Provide the Theme:Import
ThemeProvider
fromstyled-components
inApp.js
and wrap your application’s components with it. Pass thetheme
object as a prop toThemeProvider
:import React, { Fragment } from 'react'; import Header from './components/Header'; import { Container } from './styles/Container.styled'; import { ThemeProvider } from 'styled-components'; // Import ThemeProvider const theme = { /* ... theme object defined earlier ... */ }; function App() { return ( <ThemeProvider theme={theme}> {/* Wrap components with ThemeProvider */} <Fragment> <Header /> <Container> <h1>Hello World</h1> </Container> </Fragment> </ThemeProvider> ); } export default App;
-
Access Theme Values in Styled Components:
Now, you can access theme values within your styled components using the
theme
prop. For example, inHeader.styled.js
, modifyStyledHeader
to use theheader
color from the theme:export const StyledHeader = styled.header` background-color: ${({ theme }) => theme.colors.header}; /* Access header color from theme */ padding: 40px 0; `;
background-color: ${({ theme }) => theme.colors.header};
: We use destructuring in the arrow function’s parameter list to directly access thetheme
prop. Then, we accesstheme.colors.header
to get the header color defined in our theme object.
Now, the StyledHeader
’s background color is driven by the theme.colors.header
value. If you change the color in the theme
object, it will automatically update across all components using that theme value.
Global Styles for Baseline and Reset
Styled Components also allows you to define global styles, which are applied to the entire application. This is useful for setting baseline styles, resets, and common styles for HTML elements like body
, p
, a
, etc.
-
Create
GlobalStyles.js
instyles
folder:Inside the
src/styles
folder, create a new file namedGlobalStyles.js
. -
Define Global Styles:
Open
GlobalStyles.js
and add the following code:import { createGlobalStyle } from 'styled-components'; const GlobalStyles = createGlobalStyle` *, *::before, *::after { box-sizing: border-box; /* Apply border-box to all elements */ } body { background: ${({ theme }) => theme.colors.body}; /* Body background from theme */ color: hsl(192, 100%, 9%); font-family: 'Poppins', sans-serif; font-size: 1.15em; margin: 0; } p { opacity: 0.6; line-height: 1.5; } img { max-width: 100%; } `; export default GlobalStyles;
import { createGlobalStyle } from 'styled-components';
: ImportscreateGlobalStyle
function.const GlobalStyles = createGlobalStyle``...``;
: Creates a global style component usingcreateGlobalStyle
.- Within the backticks, you write CSS that will be applied globally.
-
Reset styles like
box-sizing: border-box;
-
body
styles including background color from the theme (theme.colors.body
). -
Styles for
p
andimg
elements.
-
Global Styles: CSS styles that are intended to affect the entire webpage or application, typically including resets, baseline styles for common HTML elements, and application-wide styling rules.
-
Import and Include
GlobalStyles
inApp.js
:Import
GlobalStyles
inApp.js
and render it as a component, typically at the top level, inside theThemeProvider
:import React, { Fragment } from 'react'; import Header from './components/Header'; import { Container } from './styles/Container.styled'; import { ThemeProvider } from 'styled-components'; import GlobalStyles from './styles/GlobalStyles'; // Import GlobalStyles const theme = { /* ... theme object ... */ }; function App() { return ( <ThemeProvider theme={theme}> <GlobalStyles /> {/* Include GlobalStyles component */} <Fragment> <Header /> <Container> <h1>Hello World</h1> </Container> </Fragment> </ThemeProvider> ); } export default App;
Now, the global styles defined in GlobalStyles.js
will be applied to your entire application. This includes the body background color being taken from the theme, font styles, and the box-sizing reset.
Conclusion of Fundamentals
This section covered the fundamental concepts of Styled Components. You have learned how to:
- Create basic styled components using
styled.tagname``...``;
- Nest styles within styled components
- Use props to dynamically style components
- Implement themes for consistent styling across your application
- Apply global styles for resets and baseline styling
With these fundamentals in place, you are now ready to move on to building a practical project to further solidify your understanding and explore more advanced techniques with Styled Components. The next sections will guide you through building a landing page project.