CSS selectors target and select the HTML elements you want to style. They are often treated as a solved problem, something we learn once and then rarely revisit. In reality, selectors are one of the most powerful and evolving parts of the CSS language. As modern frontend development shifts toward component-based architectures like React, selectors have quietly adapted, becoming less about global styling and more about expressing intent, state, and relationships within UI systems.
At the same time, styling on the web is no longer static. Values change at runtime. Components respond to props, user interaction, accessibility states, themes, and system preferences. The challenge is no longer how to style an element, but how to design a styling system that can respond dynamically without becoming fragile or over-coupled to JavaScript logic. This is where a deeper understanding of selectors, combined with modern CSS features becomes essential.
Specifically, CSS selectors allow you to select multiple elements at once.
They are helpful when you want to apply the same styles to more than one HTML element, because you will not repeat yourself by writing the same lines of code for different elements.
CSS selectors are also helpful when you want to make a change you only need to make the change in one place, which saves you a lot of time. CSS selectors are among the first things you need to learn when you first start writing CSS code. And there are many selectors available to choose from, along with several different ways to use them more than you may realize. This guide explores how CSS selectors work in a world driven by dynamic values, particularly in React applications. We’ll look beyond basic class selectors and dive into attribute selectors, pseudo-classes, and newer relational selectors, then connect them to runtime data using CSS variables and data attributes. The goal is to show how CSS can remain declarative, expressive, and scalable even as your UI becomes increasingly dynamic.
Rather than positioning CSS and React as competing approaches to styling, this guide treats them as complementary tools. React handles data and state, while CSS — powered by smart selectors — handles presentation and behavior. When used together intentionally, they reduce complexity, minimize unnecessary re-renders, and lead to UI code that is easier to reason about, maintain, and evolve.
With that said, there is no need to worry, you do not have to memorize everything.
Why CSS Selectors Still Matter in Modern Frontends?
CSS selectors are the grammar of the web’s visual language. Even as frameworks like React abstract UI into components, selectors remain the bridge between structure and style. Understanding them deeply lets you write smaller stylesheets, avoid specificity wars, and unlock dynamic styling patterns that scale.
This guide connects classic CSS selectors with dynamic values, especially in React-driven apps, so you can confidently style components without fighting your tools.
A Quick Mental Model
Think of selectors as questions you ask the DOM:
Which elements look like this, are located here, or are in this state?
Dynamic values are answers that change depending on props, state, or runtime conditions.
Selectors decide where styles apply. Dynamic values decide how they look right now. This cheat sheet covers the most commonly used selectors you need to know when starting out. Bookmark it so you can come back to it whenever you need a quick reminder when you are working on your next web design project.
Simple CSS Selectors
Selectors allow you to target and select specific parts of your document for styling purposes.
Simple selectors directly select one or more elements:
By using the universal selector *.
Based on the name/type of the element.
Based on the class value of the element.
Based on the ID value of the element.
By learning how the most simple selectors work, you can understand how to use the more complex ones.
The simple selectors will most often be the ones you will use the most and the ones you will be the most familiar with if you have some experience writing CSS code.
CSS Universal Selector
The universal selector, also known as a wildcard, selects everything - every single element in the document.
To use the universal selector, use the asterisk character, *.
1* {
2 property: value;
3}
4You can use the universal selector to reset the browser's default padding and margin to zero at the top of the file before you add any other styles:
1* {
2 padding: 0;
3 margin: 0;
4}
5CSS Type Selector
The CSS type selector selects all HTML elements of the specified type.
To use it, mention the name of the HTML element.
For example, if you wanted to apply a style to every single paragraph in the HTML document, you would specify the p element:
1p {
2 property: value;
3}
4The code above matches and selects all p elements within the document and styles them.
Core Selector Types (Beyond the Basics)
- Attribute Selectors
Attribute selectors shine when you want styles driven by data, not class sprawl.
1button[aria-pressed="true"] {
2 background: black;
3 color: white;
4}
5Why this matters in React:
Props often map to attributes (aria-, data-)
Styling via attributes keeps logic and visuals loosely coupled
1<button aria-pressed={isActive}>Toggle</button>
2- Pseudo-classes as State Machines
Pseudo-classes are CSS’s built-in state system.
1input:focus-visible {
2 outline: 2px solid dodgerblue;
3}
4Underrated ones worth memorizing:
:focus-visible
:focus-within
:has() (now shipping in modern browsers)
1
2.card:has(img:hover) {
3transform: scale(1.02);
4}
5:where() adds zero specificity
:is() keeps the highest specificity of its arguments
Use them intentionally to avoid cascading chaos.
Dynamic Values with CSS Variables
CSS custom properties are the missing link between React props and pure CSS.
Defining Variables at the Component Boundary
1<div style={{ '--accent': color }} className="card" />
21.card {
2border-left: 4px solid var(--accent);
3}
4Why this pattern scales:
CSS stays declarative
React only passes values, not styles
Themes become trivial
Variables Beat Inline Styles
Inline styles:
Don’t support pseudo-classes
Don’t cascade
Don’t compose
CSS variables:
Work with :hover, :focus, media queries
Cascade naturally
Are runtime-dynamic
1.card:hover {
2background: color-mix(in srgb, var(--accent), white 80%);
3}
4Data Attributes as a Styling API
Data attributes are a clean contract between logic and style.
1<div data-variant="warning" />
21[data-variant="warning"] {
2background: #fff3cd;
3color: #664d03;
4}
5This pattern:
Avoids class name explosions
Reads like documentation
Works across frameworks
Selectors in a Component World The Mistake: Styling Components Like Pages
Over-nesting:
1.app .page .card .title span {
2color: red;
3}
4The fix:
Style components, not DOM paths
Prefer flat selectors with clear ownership
1.cardTitle {
2color: red;
3}
4Then enhance with state selectors, not structure.
When to Reach for CSS-in-JS (and When Not To)
CSS-in-JS is great when:
Styles are tightly coupled to logic
You need JS math or conditions
Traditional CSS + variables wins when:
Styles depend on state but not logic
You want browser-native performance
A hybrid approach is often the sweet spot. A Practical Rule of Thumb
Selectors decide scope and state
Variables carry dynamic values
React props only pass data, not decisions
If your component API feels clean, your CSS probably is too.
CSS Class Selector
The class selector matches and selects HTML elements based on the value of their given class. Specifically, it selects every single element in the document with that specific class name.
With the class selector, you can select multiple elements at once and style them the same way without copying and pasting the same styles for each one separately.
Classes are reusable, making them a good option for practicing DRY development. DRY is a programming principle and is short for 'Don't Repeat Yourself'. As the name suggests, the aim is to avoid writing repetitive code whenever possible.
To select elements with the class selector, use the dot character, ., followed by the name of the class.
1
2.my_class {
3 property: value;
4}
5In the code above, elements with a class of my_class are selected and styled accordingly.
CSS ID Selector
The ID selector selects an HTML element based on the value of its ID attribute.
Keep in mind that the ID of an element should be unique in a document, meaning there should only be one HTML element with that given ID value. You cannot use the same ID value on a different element besides that one.
To select an element with a specific ID, use the hash character, #, followed by the name of the ID value:
1#my_id {
2 property: value;
3}
4The code above will match only the unique element with the ID value of my_id .
It's worth mentioning that it is best to try and limit the use of this selector and opt for using the class selector instead. Applying styles using the ID selector is not ideal because the styles are not reusable.
Simple CSS selectors form the foundation of everything you do in CSS. Universal, type, class, and ID selectors may look basic on the surface, but they shape how you think about structure, reuse, and intent when styling a document. Mastering these selectors isn’t about memorizing syntax — it’s about understanding how CSS sees your HTML and how styles flow through the document.
In practice, you’ll find yourself relying heavily on class selectors, occasionally using type selectors for global patterns, and reaching for the universal selector with care. ID selectors, while powerful, often introduce rigidity and specificity issues when overused. Learning when not to use a selector is just as important as knowing how it works. These early decisions directly affect how scalable, maintainable, and flexible your styles become as a project grows.
Once these simple selectors feel intuitive, more advanced selector patterns start to make sense naturally. You begin to see CSS not as a list of rules, but as a system for expressing relationships, state, and meaning within your UI. This mental shift is what allows you to write cleaner stylesheets and avoid fighting the cascade later on.
In the next guide, we’ll take a deeper dive into attribute selectors — a powerful and often overlooked tool that allows you to style elements based on their attributes and values. Attribute selectors open the door to more semantic, data-driven styling and pair especially well with modern frameworks like React. If simple selectors are the vocabulary of CSS, attribute selectors are where the language really starts to get expressive.
Happy coding, and enjoy the journey of turning simple selectors into powerful styling tools, and remember: clean selectors today mean fewer headaches tomorrow.