Every year in October, the biggest international react conference takes place in Goa, India. Yes, I am talking about if you've missed to watch it live. If you prefer reading over watching videos, then this blog is just for you! Let's dive into it.
What is StyleX?
StyleX is Meta's new, scalable styling library that is now used as the primary system behind platforms like Facebook, Instagram, and WhatsApp. It addresses the pain points experienced with CSS-in-JS approaches, particularly in massive React applications. By offering a hybrid solution that blends the best features of both atomic CSS and static CSS, StyleX offers an efficient, modular, and scalable alternative.
How and Why did Meta create StyleX?
- Meta built StyleX to address specific challenges encountered with traditional CSS-in-JS libraries in large-scale projects:
Unused Styles: As projects grow, CSS often accumulates unused rules, bloating the stylesheet.
Performance Issues: CSS-in-JS solutions can result in large CSS files or performance bottlenecks, especially when bundled with the application.
CSS-in-JS Library Size: Many popular libraries used for styling in JavaScript add unnecessary weight to the bundle, impacting load times.
Introduction of StyleX: It was created in 2019 as part of a Facebook UI revamp and they made it open-source in December 2023.
CSS Optimization: Before using StyleX, a single page on Facebook would load around 15-45MB of CSS styles. This was drastically reduced to around 200-300KB with StyleX by utilizing a single CSS bundle.
Purpose of StyleX: It was developed to effectively manage the complexities of styling at scale. It addresses the challenges that arise when numerous developers create thousands of components, which often leads to specificity conflicts within CSS. By providing a structured framework for styling, StyleX helps maintain consistency and clarity in the styling process.
Atomic Class Generation: From the outset, StyleX consistently generates atomic classes, accepting the trade-off of having multiple class names per component for improved maintainability and reduced styling conflicts.
Key Features of StyleX:
Atomic CSS Generation: StyleX employs atomic CSS generation, which means it creates small, reusable classes for each style rule. This approach not only minimizes redundancy in the final CSS bundle but also improves performance by reducing the overall size of the stylesheets.
CSS Deduplication: By generating unique class identifiers for each style, StyleX effectively eliminates duplicate styles. This deduplication process ensures that each property-value pair is rendered only once, further contributing to a leaner CSS output.
“The Last Style Applied Always Wins!”: StyleX follows a predictable styling rule where the last style applied takes precedence. This feature simplifies debugging and enhances developer confidence, as it mitigates concerns about conflicting style rules.
Optimized for React: Designed specifically for React applications, StyleX integrates seamlessly into the React ecosystem. It allows developers to define styles directly within their components, fostering a more cohesive development workflow.
Flow and TypeScript Support: StyleX is written in "Flow" (created by Meta) and it also provides robust support for TypeScript, enabling type-safe APIs for styles and themes. This type safety enhances code reliability and maintainability, making it easier to manage complex styling scenarios.
Flexible Conditional Styling: With StyleX, developers can apply styles conditionally based on component states or props. This flexibility allows for dynamic styling that adapts to user interactions or changes in application state.
Scoped Styling: The scoped styling feature of StyleX ensures that styles are applied only to the components they are intended for. This prevents unintended side effects and specificity issues that often arise in larger codebases.
Fewer Runtime Calculations: StyleX minimizes runtime calculations by bundling all styles into a static CSS file at compile time. This optimization leads to faster rendering times and improved performance, especially in larger applications.
Better Code Maintainability: By co-locating styles with their respective components and utilizing atomic classes, StyleX promotes better code maintainability. Developers can easily understand and modify styles without sifting through extensive stylesheets.
Minimal CSS Output: The use of atomic CSS results in minimal CSS output, which is particularly beneficial for performance. As projects grow in size and complexity, StyleX ensures that the CSS bundle remains manageable without sacrificing functionality.
Works Well for Projects of All Sizes: While StyleX is suitable for projects of all sizes, it truly excels in larger applications. Its architecture is designed to handle the complexities of extensive styling needs without compromising on performance or maintainability.
Let's see how it works 🧑💻
The code examples in this article are written in React, and we will primarily work with two components, App.jsx and Button.jsx. Let's take a look at the basic structure of these components before we add styles.
import Button from "./components/Button";
const App = () => {
return (
<div>
<h1>StyleX by Meta</h1>
<Button text="Get Started" />
</div>
);
};
export default App;
// Button.jsx
import PropTypes from "prop-types";
const Button = ({ text }) => {
return <button>{text}</button>;
};
Button.propTypes = {
text: PropTypes.string.isRequired,
};
export default Button;
Adding styles to pseudo-classes
import PropTypes from "prop-types";
import * as stylex from "@stylexjs/stylex";
const styles = stylex.create({
base: {
fontSize: 18,
backgroundColor: {
default: "black",
":hover": "blue",
},
color: "white",
},
});
const Button = ({ text }) => {
return <button {...stylex.props(styles.base)}>{text}</button>;
};
Button.propTypes = {
text: PropTypes.string.isRequired,
};
export default Button;
With StyleX, it's pretty simple to add styles to pseudo-classes. In the previous example, backgroundColor was a string. Here, we convert it to an object with the default value and a pseudo-class.
Let's see how "last style applied always wins"
Let's extend the previous example to see how we can create different variants of this button.
const styles = stylex.create({
base: {
fontSize: 18,
backgroundColor: {
default: "teal",
":hover": "blue",
},
color: "white",
width: {
default: "100px",
"@media (max-width: 476px)": "100%",
},
},
highlighted: {
backgroundColor: "orange",
},
danger: {
backgroundColor: "red",
},
primary: {
backgroundColor: "green",
},
});
const Button = ({ text, isHighlighted, variant }) => {
return (
<button
{...stylex.props(
styles.base,
isHighlighted && styles.highlighted, // conditional styling
styles[variant]
)}
>
{text}
</button>
);
};
Button.propTypes = {
text: PropTypes.string.isRequired,
isHighlighted: PropTypes.bool,
variant: PropTypes.oneOf(["danger", "primary"]),
};
Let's add a few more namespaces to stylex.create method and provide them with different background colors. Additionally, we are accepting 2 new props within our Button component. isHighlighted is a boolean prop that we use to apply the highlighted namespace. And variant is a prop that we use to apply the primary, danger or highlighted namespace.
// App.jsx
import Button from "./components/Button";
const App = () => {
return (
<div>
<h1>StyleX by Meta</h1>
<div {...stylex.props(styles.main)}>
<Button text="Base Button" />
<Button text="Highlighted Button" isHighlighted />
<Button text="Danger Button" isHighlighted variant="danger" />
<Button text="Primary Button" variant="primary" />
</div>
</div>
);
};
export default App;
We create a few more copies of the Button component with different props being passed on. This is how our app looks like now.
In this example, the override namespace currently allows any properties. However, StyleX gives us the capability to limit which properties can be overridden. This feature becomes particularly useful when using TypeScript.
import type { StyleXStyles } from "@stylexjs/stylex";
type Props = {
// ...
style?: StyleXStyles<{
color?: string,
backgroundColor?: string,
}>,
};
This limitation ensures that only the backgroundColor and color properties can be overridden.
How does atomic classes work (internals)
That's a wrap 🎉
Hurray! We have successfully got a gist of working with StyleX. Thank you for reading through this article. I hope it provided a good understanding of what is StyleX, how did Meta create it, and how to use it. Please share your thoughts/queries in the comments section or on
SOCIAL SHARE CARD GENERATOR