CSS In JS is a practice that allows one to write CSS properties for components in JavaScript. In Runtime CSS In JS, the styles are interpreted and applied at the runtime. It involves using JavaScript libraries to combine styles with component code without needing to use external stylesheets, i.e. writing CSS in .js
files, so that they can work as JS modules. This approach aims to tackle some known issues while working with CSS stylesheets like Scoping, Extensibility, Portability, Specificity, Maintenance etc.
How is it done?
There are different ways to implement CSS In JS, most commonly using either framework-dependent or framework-agnostic libraries. Styled components are among the most popular of them with over 30,000+ stars on GitHub.
This is how CSS In JS using styled components in React looks like -
import styled from "styled-components";
// Defining the styles for the element
const Title = styled.h1`
color: red;
border: 1px solid blue;
padding: 10px;
`;
// Using the styled component
const App = () => <Title>Hello World!</Title>;
Another popular library for writing CSS styles with JavaScript is @emotion/css. It is framework-agnostic and needs no additional setup, babel plugin, or other config changes for primitive use.
import { css } from '@emotion/css'
const color = 'white';
const CSSInJs = () => {
return (
<div
className={css`
background-color: red;
font-size: 40px;
&:hover {
color: ${color};
}
`}
>
Hello CSS!
</div>
);
};
Some popular CSS-In-JS libraries are - Styled JSX, styled-components, Emotion, Treat, TypeStyle, Fela, Stitches, JSS, Goober, and Compiled.
Some Pros of using CSS-In-JS
Maintenance
Large enterprise projects sometimes require hundreds of stylesheets needed to be maintained on a per-component basis, maintaining them and ensuring that there is minimal repetition to avoid having to deal with large bundle sizes is a task. CSS-In-JS simplifies that by eliminating the need for external stylesheets. A developer however needs to be well-versed in both CSS and JS to be able to seamlessly maintain projects with in-component CSS-In-JS.
Minimal Scoping and Specificity problems
Since all the styles are maintained in local scope, there is no need of using stricter selectors or preventing name clashes.
Styles could be written specifically for one component, without introducing specificity issues.
Dynamic Styling
The ability to apply conditional CSS, ease of theming, and adding styles based on certain conditions, states or prop values can all be achieved using CSS-In-JS.
Some Cons of CSS-In-JS
Increase in Bundle Size
It is understandable, the JavaScript for your CSS-In-JS library will also be included in your application bundle. Emotion is 7.9 kB min-zipped and styled components is 12.7 kB. So neither library is huge, but it all adds up :) (react
+ react-dom
is 44.5 kB for comparison.)
Server-Side Rendering Support
When it comes to supporting server-side-rendering, there may be many unknown issues that could pop up using CSS-In-JS. Using external component libraries may also not be easy enough. Many CSS-In-JS libraries receive issues related to SSR support. It could be that multiple instances of the library get loaded at once.
While integrating component libraries, they may not give you full control over the order in which styles are inserted. (Example issue).
Performance Considerations
CSS-In-JS uses JavaScript to process CSS from JavaScript components, this CSS is then injected into DOM. The more the number of components, the more time it would take to make the first paint by the browser.
CSS caching is used to improve successive page loading time, there is no caching involved in CSS-In-JS. Dynamically generated class names make this more complicated.
TL: DR;
In this post, we discussed at length the philosophy of CSS-In-JS, the ways to implement it and the pros and cons of using it.
There are different advantages and disadvantages associated with both CSS modules and CSS-In-JS, at the end, it depends on your use case, the external component libraries, design systems, and developer skill sets to determine which approach would be more appropriate for your app :)