In the attributes article you met id and class for the first time and learned the headline difference: an id is unique, a class is shared. That’s the one-sentence version. But these two attributes do so much heavy lifting in real projects that they deserve a proper look on their own.
Almost every line of CSS you ever write, and a huge chunk of the JavaScript, depends on being able to point at the right element. Classes and IDs are how you put a handle on an element so the other two layers can grab it. Get comfortable with them now and the rest of frontend will feel a lot less mysterious.
By the end of this article you’ll know exactly how to write classes and IDs, the rules the browser enforces, how CSS and JavaScript use them differently, and the naming habits that stop a project from turning into spaghetti.
Why elements need labels
A web page is a tree of elements — dozens, sometimes thousands of them. When you want to make one paragraph blue, or hide one menu, or run code when one button is clicked, you need a way to say “that one, not the others.”
You could try to target elements by their tag name alone, but that’s a blunt instrument. Writing a rule for p styles every paragraph on the page. What you usually want is something more precise: “the paragraphs that are part of the intro,” or “this specific call-to-action button.” That precision is exactly what class and id give you. They’re the names you attach to elements so you can refer to them later.
<p class="intro">This paragraph belongs to the intro group.</p>
<button id="checkout">Check out</button>
The class="intro" says this is one of the intro paragraphs. The id="checkout" says this is the one specific checkout button. Neither attribute changes how the element looks or behaves on its own — they’re labels, nothing more. Their value comes from CSS and JavaScript using them.
The class attribute up close
A class is a shared label. The two defining features are: many elements can have the same class, and one element can have many classes.
One class, many elements
Give a group of elements the same class and you can style or script them all at once:
<div class="card">First product</div>
<div class="card">Second product</div>
<div class="card">Third product</div>
All three divs share the class card. Later, a single CSS rule for .card styles all of them — set the padding, border, and shadow once, and every card gets it. That’s the whole point of classes: define a look or behaviour once, reuse it everywhere.
Many classes, one element
An element’s class attribute can hold several class names, separated by spaces:
<button class="btn btn-primary btn-large">Buy now</button>
That button carries three classes: btn, btn-primary, and btn-large. Each one can contribute something — btn the shared button look, btn-primary the colour, btn-large the size. You mix and match them like ingredients. This is how design systems stay flexible: small, single-purpose classes that combine.
Spaces separate classes, so don't put spaces inside one
The space is the separator between class names. That means a single class name can’t contain a space. class="card big" is two classes (card and big), not one class called “card big”. If you need a multi-word name, join the words with a hyphen: class="card-big". Getting this wrong is a classic beginner bug — your CSS rule silently matches nothing because the class you wrote doesn’t exist the way you think it does.
How CSS targets a class
In CSS, you select a class by putting a dot (.) in front of its name. You don’t need to know CSS deeply yet — just notice the pattern:
.card {
border: 1px solid #ddd;
padding: 16px;
}
That rule reaches into the HTML, finds every element whose class includes card, and applies the styles. The dot is the signal “this is a class name.” Change the HTML to add class="card" to a new element and it instantly picks up the same styling — no extra CSS needed.
How JavaScript targets a class
JavaScript can grab elements by class too. The common method is querySelectorAll, and you hand it the same .card selector you’d use in CSS:
const cards = document.querySelectorAll(".card");
console.log(cards.length); // 3
That returns every matching element so your code can loop over them — add a click handler to each card, for example. Again, the same little .card selector works in both CSS and JavaScript, which is part of why classes are so central.
The id attribute up close
An id is a unique label. Where class says “one of these,” id says “the one and only.”
<header id="top">...</header>
<main id="content">...</main>
<footer id="bottom">...</footer>
Each of those IDs should appear exactly once on the page. id="content" points at one specific element and nothing else. That uniqueness is the whole character of an id: it’s a precise address for a single element.
How CSS and JavaScript target an id
In CSS, you select an id with a hash (#) instead of a dot:
#content {
max-width: 800px;
margin: 0 auto;
}
In JavaScript, the cleanest way to grab a single element is getElementById, which takes the id name without the #:
const main = document.getElementById("content");
There’s also querySelector("#content") if you prefer the selector syntax. Either way, because the id is unique, you get back exactly one element — no looping, no guessing which one you meant.
IDs also work as page anchors
You already saw this in the links and images article: an id doubles as a destination you can link to. Put an id on a heading, and a link with # plus that id jumps straight to it:
<h2 id="pricing">Pricing</h2>
...
<a href="#pricing">Jump to pricing</a>
Click that link and the browser scrolls down to the pricing heading. This is how in-page navigation and “back to top” links work, and it’s a job only id can do — classes can’t be link targets.
IDs connect labels to form fields
One more important job for id, which you met in forms and inputs: a <label>’s for attribute points at an input’s id to tie them together:
<label for="email">Email</label>
<input type="email" id="email" />
Because the for="email" matches id="email", clicking the label focuses the input — better usability and better accessibility. This pairing is one of the most common and legitimate uses of id in everyday HTML.
id vs class: which one, when?
Here’s the decision in plain terms. Reach for class when you’re describing a category of elements — anything you might want more than one of, or anything you’re styling. Reach for id when you need to point at one specific element, usually as a link target or a hook for a single piece of JavaScript.
Default to class for styling
A good rule of thumb: style with classes, not IDs. Even when an element is genuinely unique, a class still works for styling it, and it keeps your options open if you ever need a second one. IDs are best kept for the jobs only they can do — being a link anchor (#section) and connecting a label to its input (for/id). Many teams avoid IDs in CSS entirely. You won’t go wrong defaulting to classes for appearance and saving IDs for anchors and form labels.
There’s also a technical reason styling teams prefer classes: in CSS, an id selector is “heavier” than a class selector, so an id-based rule can be stubbornly hard to override later. You’ll meet that idea formally when you learn about CSS specificity. For now, just know that leaning on classes keeps your styling predictable.
Naming rules the browser cares about
Most of the time you can name things however you like, but a few rules are worth knowing so you don’t trip over them.
- Case matters.
class="Card"andclass="card"are different classes, andid="Top"is not the same asid="top". Pick a casing style and stick to it — lowercase is the overwhelming convention. - No spaces inside a single name. As covered above, a space starts a new class. Use hyphens to join words.
- IDs must be unique. Two elements with the same
idis invalid HTML. The page may still render, butgetElementByIdwill only ever find the first one, which leads to baffling bugs. - Don’t start a name with a digit if you can avoid it. Names like
id="1col"cause real headaches in CSS selectors. Start with a letter and you’ll never have to think about it.
Duplicate IDs are a silent trap
Putting the same id on two elements doesn’t throw an obvious error — that’s what makes it dangerous. CSS might style both, but JavaScript’s getElementById returns only the first match, and assistive technologies and in-page links get confused. If you find yourself wanting to reuse an id, that’s the universe telling you to use a class instead. One id, one element, one page — no exceptions.
Naming conventions that keep things sane
The browser only enforces the rules above, but on real projects the style of your names matters just as much. Good names make a codebase readable; cryptic ones make it a guessing game.
- Describe the purpose, not the appearance.
class="error-message"stays meaningful even if you later change errors from red to orange.class="red-text"lies the moment the design changes. - Be consistent. Most teams use lowercase words joined by hyphens —
class="nav-link",class="product-card". This is sometimes called kebab-case, and it reads cleanly. - Avoid noise names.
class="x1",class="div2",class="thing"tell the next person (often future-you) nothing. A few extra characters of clarity pay for themselves many times over.
You’ll later run into more structured systems for naming — BEM is a popular one that gives you patterns like card__title and card--featured. You don’t need any of that yet. Clear, descriptive, hyphenated names will carry you a very long way.
A small example tying it together
Here’s a tiny, realistic snippet that uses both attributes the way you’d see in real code:
<section id="features" class="section">
<h2 class="section-title">What you get</h2>
<article class="feature-card">
<h3 class="feature-card__title">Fast</h3>
<p class="feature-card__text">Loads in milliseconds.</p>
</article>
<article class="feature-card">
<h3 class="feature-card__title">Secure</h3>
<p class="feature-card__text">Encrypted end to end.</p>
</article>
</section>
Read it like a person, not a parser. The id="features" is a unique anchor — you could link to #features from a navigation menu. The class="section" and class="feature-card" are shared categories: there are two feature cards here, and a CSS rule for .feature-card would style both identically. The hyphenated, purpose-describing names tell you what every element is at a glance. That’s classes and IDs working exactly as intended.
Wrapping up
Classes and IDs are small attributes with an outsized role: they’re how you put names on elements so CSS can style them and JavaScript can find them.
classis a shared label. Many elements can have the same class, and one element can have several classes (space-separated). CSS targets it with a dot (.card); JavaScript withquerySelectorAll(".card").idis a unique label — exactly one per page. CSS targets it with a hash (#content); JavaScript withgetElementById("content"). IDs also serve as link anchors and connect<label>to inputs viafor.- Default to classes for styling. Save IDs for the jobs only they can do — anchors and form labels.
- Follow the rules (case-sensitive, no inner spaces, IDs unique, don’t start with a digit) and name for purpose with lowercase hyphenated names.
These attributes are the connective tissue of frontend development. The moment you start writing CSS in earnest, you’ll be reaching for .class selectors constantly — and now you understand exactly what they’re pointing at and why.