Styling React components is an essential part of building front-end applications. There are several ways in which we can achieve our desired styling in React. Not only it helps make the applications aesthetically pleasing, but also improves the overall user experience (UX). This is not a be-all guide to styling React components, but a starting point. My aim with this post will be to enlist few ways in which you can start adding styles to your monotonous React application.
The best way to learn is by doing. Hence, at the end of this post, I am also adding a code-sandbox so that you can practice all the examples covered here.
Show me the good stuff
Inline Style
Adding inline styles to React is no different as compared to adding styles to normal HTML DOM elements. You use the same style
attribute to add the inline styles. The only difference here is that:
- The value of the
style
attribute has to be anobject
- The CSS properties follow camelCase
For example:
<label htmlFor="name" style={{paddingRight: '10px'}}>Name</label>
The style
attribute will take an object with camelCased CSS properties. If you look closely, the object that we are passing is inside another {
and }
. The attribute does not accept a CSS string. It is more efficient and prevents XSS security holes.
Few examples depicting the camelCasing for CSS properties:
padding-right
–>paddingRight
margin-left
–>marginLeft
background-image
–>backgroundImage
The exception is aria-*
and data-*
attributes, which should be lowercased. For example, you can keep aria-label
as aria-label
.
An example of a styled object will be:
import React from "react";
import { render } from "react-dom";
// Main App component
const App = (props) => {
// style object
const lableStyle = {
padding: 10, // will by default add 'px'
marginRight: '1rem', // have to explicitly add the units if you want anything other than px
backgroundColor: '#efefef',
borderWidth: 2,
borderStyle: 'solid',
borderColor: '#000',
borderRadius: 50,
display: 'inline-block'
}
return (
<div>
<h1>Styling in React by Aditya Tyagi</h1>
<form>
{/* Passing style javascript object */}
<label htmlFor="name" style={lableStyle}>Name</label>
<input type="text" name="name"/>
</form>
</div>
);
};
render(<App />, document.getElementById("root"));
This will result in:

And the camelCase will be rendered just as any style renders in the DOM.

Before we move to the next segment, I would like to point out that the styles are not auto-prefixed. Vendor prefixes, also known as CSS browser specific prefixes, should begin with a capital letter. There has been just one exception, and that is ms
. You can explore here for more!
For example:
const styleObj = {
WebkitTransition: 'all 4s ease', // checkout the capital 'W' here
msTransition: 'all 4s ease', // 'ms' is lowercase
MozTransition: 'all 4s ease',
OTransition: 'all 4s ease',
transition: 'all 4s ease'
};
An important thing to note here is that the React official docs recommends to NOT use the inline style method.
Some examples in the documentation use
– reactjs.orgstyle
for convenience, but using thestyle
attribute as the primary means of styling elements is generally not recommended.
Dynamic Inline Styles
Dynamic styling is an integral part of understanding the entire process of styling React components. React, even though recommends not to use the inline styling method, it does is on-board to use them to dynamically set styling on the DOM elements. By “dynamically”, I mean when there is state change. For this, you need to have a good grasp on how useState
hook and state change works. If you want a refresher, you can check this out.
Let’s understand this with a simple example of changing the input border and background color when form is submitted with no input.
import React, { useState } from "react";
import { render } from "react-dom";
// Main App component
const App = (props) => {
const [name, setName] = useState();
const [isValid, setIsValid] = useState(true);
// style object
const lableStyle = {
padding: 10, // will by default add 'px'
marginRight: '1rem', // have to explicitly add the units if you want anything other than px
backgroundColor: '#efefef',
borderWidth: 2,
borderStyle: 'solid',
borderColor: '#000',
borderRadius: 50,
display: 'inline-block'
}
const nameChangeHandler = (e) => {
setName(e.target.value)
}
const submitHandler = (e) => {
e.preventDefault();
if(!name) {
setIsValid(false);
return;
}
}
return (
<div>
<h1>Styling in React by Aditya Tyagi</h1>
<form onSubmit={submitHandler}>
{/* Passing style javascript object */}
<label htmlFor="name" style={lableStyle}>Name</label>
{/* Conditionally set border for invalid input */}
<input style={{border : !isValid ? '3px solid red' : ''}} value={name} type="text" name="name" onChange={nameChangeHandler}/>
<button type="submit">Submit</button>
</form>
</div>
);
};
render(<App />, document.getElementById("root"));
This will toggle the border color of the input with the state of isValid
. The result will look something like:

Using Stylesheets and Class Names
The most sought after way to add styling to any DOM element in React is via classes. In React, we add classes using the className
attribute on the DOM elements.
<h1 className="main-heading">Styling in React by Aditya Tyagi</h1>
To give CSS properties to the class main-heading
we’ll use an external CSS stylesheet. We’ll then import that stylesheet in our App.js
file or whichever file we want to use it in.
import "./style.css";
Yes, it is that easy. I have created a file (also available in the code-sandbox) style.css
and imported it in App.js
/* style.css */
.main-heading {
background-color: aqua;
}
And Voila! You can now style the main heading.

Setting CSS classes dynamically
The one rule we need to learn and respect is that the className
will always be a string. This is besides our learning of adding CSS style object dynamically above. Combining the two and harnessing the power of template literals, we can set a class dynamically.
To understand this, we’ll follow the same example we used above about changing the border color to red on invalid submission.
/* style.css */
.main-heading {
background-color: aqua;
}
.invalid {
border: 2px solid red;
background-color: #ffcfcf;
}
Using the invalid
class dynamically on the input, we’ll witness a change in border and background color.
// in App.js
{/* Conditionally set border and background color for invalid input */}
<input
className={`${!isValid ? " invalid" : ""}`}
value={name}
type="text"
name="name"
onChange={nameChangeHandler}
/>
And the result will be:

Styled Components
The issue with the approaches above is that the styles that you import in one component DOES NOT scope to that only. It is accessible in the global scope and thus can lead to unforeseen issues, like classes over-writing each other. To resolve this and to scope the style to a particular component, I would like to introduce you “styled-components“. This library brought a significant change in styling React components and brought a different perspective to it!
Here, I will try to give you a formal introduction to this package but if you want to dive deeper, feel free to explore!
The styled-components package helps you to build React components that have certain styles attached to it and these styles affect only them. The styles attached to these components are scoped.
Install the package using:
npm install --save styled-components
The code-sandbox at the end of the blog already has this package installed. So, please feel free to practice there.
To understand the working of styled-components
, let’s try to style the submit button in our form.
// in App.js
// import
import styled from 'styled-components';
// Creating the styled button using the "styled" object imported from "styled-components"
// It will return a styled React component
const StyledButton = styled.button`
display: inline-block;
border-radius: 3px;
padding: 0.5rem 0;
margin: 0.5rem 1rem;
width: 11rem;
background: #000;
color: white;
border: 2px solid white;
`;
The first thing is to import styled
from styled-components
library. This will help us to create styled React components. We use tagged template literal syntax to create styled components. The tagged template literal is not specific to React or this library. It is a JavaScript feature.
The imported styled
object has several methods. Here we are accessing the button
method. Here, the method names are nothing but the DOM elements. The styled
object have methods for all HTML elements.
Example:

Anything passed between the back-ticks after the method, will be passed to that method, just in a special way. Please go through this to learn more about it.
For :focus
and other pseudo-classes, you can use the &
symbol. You do not have to use the selectors
like button
.
const StyledButton = styled.button`
display: inline-block;
border-radius: 3px;
padding: 0.5rem 0;
margin: 0.5rem 1rem;
width: 11rem;
background: #000;
color: white;
border: 2px solid white;
&:hover {
opacity: 0.5;
cursor: pointer;
}
`;
By default, the component that is returned by styled
will apply all the props that you pass to it. So, you can still add onClick
prop and others like it on the StyledButton
component.
Using it in App.js
form:
<StyledButton type="submit">Submit</StyledButton>

If you now inspect the button in dev tools, you’ll see 2 classes. The classes might be different for you as the styled-components
library generate these classes for you. It guarantees that these class names are unique and hence resolves the scoping issue.

Dynamically Update Styled Components
As we already know that the component returned by the styled
object will also have all the props
passed to it. Therefore, using this, we can now dynamically update styled component.
To understand this with an example, we’ll again go back to our invalid form and border changing example and try to update the input
field with styled component.
We’ll be passing an invalid
prop to the StyledInput
component and use that for dynamic styling. The passed prop will then be accessible on the props
which is in the arrow function.
<StyledInput
invalid={!isValid} // prop
className={`${!isValid ? " invalid" : ""}`}
value={name}
type="text"
name="name"
onChange={nameChangeHandler}
></StyledInput>
And the corresponding StyledInput
will be something like:
const StyledInput = styled.input`
border: 1px solid ${(props) => (props.invalid ? "red" : "black")};
background-color: ${(props) => (props.invalid ? "#ffcfcf" : "")};
`;
As a result, we can now dynamically update styling.

Media Queries and Styled Components
Adding media queries to styled-components is pretty straightforward. An example, should be enough.
const StyledButton = styled.button`
display: inline-block;
border-radius: 3px;
padding: 0.5rem 0;
margin: 0.5rem 1rem;
width: 11rem;
background: #000;
color: white;
border: 2px solid white;
&:hover {
opacity: 0.5;
cursor: pointer;
}
@media screen and (min-width: 768px) {
background: pink;
color: black;
border: 1px solid black;
}
`;
And this will update the button styling for view-ports greater than 768px.

CSS Modules
You can take your CSS and styling work in React applications to the next level with CSS Modules. It is not mandatory, but I like the separation of CSS from my HTML. It’s easy to read and work with. CSS Modules help solve the scoping problem of CSS classes while still using CSS external stylesheets.
NOTE: This will work only with apps that are configured to use this, because there are certain code transformations that happen behind the scenes. The code-sandbox that I have presented you with, is already configured.
Here, we’ll be styling our submit button as an example. For this, we’ll move all the current button styling to style.css
file and then import the file in a special way, using a special syntax.
// import
import styles from "./style.module.css";
The file name should ALWAYS follow this naming convention to work properly.
<fileName>.module.css
So, in our case, the file name is style.module.css
All the classes, like .button
we have added to the stylesheet will be present on the object styles
present in the import statement.
You can use it like this:
<button type="submit" className={styles.button}>Submit</button>
This will produce the same results as above.

The way it generates the class name ensures it is unique throughout the project so that it never encounters the scoping problem. Here, we access the classes as properties.
Dynamic Styles with CSS Modules
To dynamically set CSS classes, we will again use template literal. We will follow the same example we have been using. We’ll update the styling of the input on invalid form submission.
className={`${!isValid ? styles.invalid : ""}`}
Bonus: A playground
The example followed in this blog post has been around a form. To explore best practices around working with forms in React, you can refer this guide.
This wraps up a detailed account of 4 different ways of styling React components, both static and dynamic. I hope you could follow and found it helpful.
1 comment / Add your comment below