Classes & IDs
Two attributes connect your HTML to everything else on the page. A class puts an element into a group, and an id gives one element a unique name. CSS uses them to choose what to style, JavaScript uses them to find elements, and other HTML attributes use ids to point at each other.
You met both briefly in HTML Attributes. In this lesson you will learn the naming rules, how to combine several classes, all the places an id is used as a target, and how CSS and JavaScript work with each one.
class or id?
class | id | |
|---|---|---|
| Meaning | "This element belongs to a group" | "This is the one element called..." |
| How many elements can share it | Any number | Exactly one per page |
| Values per element | Several, separated by spaces | One |
| CSS selector | .price | #checkout |
| Typical jobs | Styling, marking a state such as selected | Jump links, labels, ARIA references, one element in JavaScript |
A simple rule of thumb: style with classes, point with ids. If you are about to write the same id twice, you wanted a class.
Naming rules and good names
The rules from the HTML standard are short:
- An
idmust be unique on the page, must have at least one character and must not contain spaces. - A
classvalue is a list of names separated by spaces. Each name can be anything without a space. - Both are case-sensitive:
Price,priceandPRICEare three different names.
HTML allows an id such as 2026-results, but a CSS selector cannot start with a digit, so #2026-results fails in CSS and in querySelector(). Start every name with a letter and you never meet this problem.
Good habits make names easy to read and remember:
- Use lowercase words joined by hyphens:
order-summary,main-menu. This style is called kebab-case. - Name things by what they are or do, not by how they look.
noticestays true after a redesign;red-boxbecomes a lie the day the box turns blue. - Keep names short but clear:
btn-primaryis fine,b1is not.
Larger projects often follow a naming system. A popular one is BEM (Block, Element, Modifier): a block such as card, its parts such as card__title, and variations such as card--featured. You do not need it for small pages, but you will recognise it in other people's code.
Combining several classes
One element can belong to many groups at once. Each class adds its own styles, and the order you write them in the attribute does not matter.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Cricket academy batches</title>
<style>
body { font-family: Arial, sans-serif; }
.batch { border: 1px solid #bbb; border-radius: 8px; padding: 10px 14px; margin: 8px 0; max-width: 340px; }
.new { border-color: seagreen; }
.new::after { content: " NEW"; color: seagreen; font-weight: bold; }
.full { opacity: 0.55; }
.batch.full.new { outline: 3px dashed orange; }
</style>
</head>
<body>
<h1>Rohtak Cricket Academy</h1>
<p class="batch">Under-12, mornings, ₹1,500 per month</p>
<p class="batch new">Under-16, evenings, ₹1,800 per month</p>
<p class="batch full">Under-19, weekends, ₹2,000 per month</p>
<p class="full new batch">Girls' batch, evenings, ₹1,500 per month</p>
</body>
</html>Every card is a batch. The second also gets the green styles of new, the third fades because it is full, and the last one gets both extras. The selector .batch.full.new, with no spaces, matches only elements that have all three classes, which is why only the girls' batch gets the orange outline.
ids as targets
Many features need to point at one exact element, and they always do it with an id.
| Feature | How it points at the id |
|---|---|
| Jump link to a section | <a href="#fees"> |
| Label for a form control | <label for="email"> |
| Extra description for screen readers | aria-describedby="email-hint" |
| Suggestions list for an input | <input list="cities"> |
| Button that opens a popover | popovertarget="menu" |
| Control placed outside its form | form="signup" |
Notice that only the link uses a #. All the other attributes take the plain id.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Admission FAQ</title>
<style>
section { padding: 8px 12px; margin: 12px 0 160px; border-left: 4px solid #ddd; }
:target { border-left-color: crimson; background: #fff3f3; }
small { display: block; color: #555; }
</style>
</head>
<body>
<h1>Admission questions</h1>
<nav>
<a href="#documents">Documents needed</a> |
<a href="#hostel">Hostel</a> |
<a href="#enquiry">Ask a question</a>
</nav>
<section id="documents">
<h2>Which documents do I need?</h2>
<p>Class 12 marksheet, ID proof and two photographs.</p>
</section>
<section id="hostel">
<h2>Is there a hostel?</h2>
<p>Yes, for girls and boys, with mess food included.</p>
</section>
<section id="enquiry">
<h2>Ask a question</h2>
<label for="mobile">Mobile number</label>
<input id="mobile" name="mobile" type="tel" aria-describedby="mobile-hint">
<small id="mobile-hint">We reply on SMS within one working day.</small>
</section>
</body>
</html>Click "Hostel": the page scrolls to the section and the CSS :target pseudo-class highlights it, because it is the element named in the URL's fragment. Click the words "Mobile number" and the cursor jumps into the box, thanks to for and id. A screen reader also reads the hint, because of aria-describedby.
How CSS uses them
In CSS, a dot selects a class and a hash selects an id:
.price { color: #138808; } /* every element with class="price" */
#checkout { margin-top: 24px; } /* the one element with id="checkout" */
.card.featured { border-width: 3px; } /* elements with BOTH classes */
.card .price { font-size: 1.2rem; } /* a .price somewhere inside a .card */Watch the space: .card.featured means one element with both classes, while .card .price means a .price element inside a .card element.
When two rules disagree, the one with the stronger selector wins. An id selector is stronger than any number of class selectors, so styles written on ids are very hard to override later. That is the main reason to style with classes. The details are in CSS Selectors and Cascade, Specificity & Inheritance.
How JavaScript uses them
JavaScript finds elements with the same selectors as CSS, and changes classes through the classList property.
| Code | What it does |
|---|---|
document.getElementById("total") | Finds the element with that id (no #) |
document.querySelector("#total") | Same result, using a CSS selector |
document.querySelectorAll(".seat") | Finds every element with that class |
el.classList.add("selected") | Adds a class |
el.classList.remove("selected") | Removes a class |
el.classList.toggle("selected") | Adds it if missing, removes it if present |
el.classList.contains("selected") | Returns true or false |
Adding and removing classes is the cleanest way to change how something looks from JavaScript: the script decides the state, and the stylesheet decides what that state looks like.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Bus seat picker</title>
<style>
.seat { width: 48px; height: 40px; margin: 4px; border: 1px solid #888; background: white; border-radius: 6px; }
.seat.selected { background: seagreen; color: white; }
.seat.booked { background: #ccc; }
</style>
</head>
<body>
<h1>Jaipur to Pune sleeper bus</h1>
<p>
<button type="button" class="seat">1A</button>
<button type="button" class="seat booked" disabled>1B</button>
<button type="button" class="seat">2A</button>
<button type="button" class="seat">2B</button>
</p>
<p id="total">No seats selected.</p>
<script>
const total = document.getElementById("total");
for (const seat of document.querySelectorAll(".seat")) {
seat.addEventListener("click", () => {
seat.classList.toggle("selected");
const chosen = document.querySelectorAll(".seat.selected").length;
total.textContent = `${chosen} seat(s) selected: ₹${chosen * 1299}`;
});
}
</script>
</body>
</html>Each click toggles the selected class, the CSS turns the seat green, and the script counts the selected seats with the selector .seat.selected. The booked seat is a disabled button, so it cannot be clicked. You will learn these methods properly in The DOM: Selecting Elements.
Common mistakes
- Writing the dot or hash in HTML.
class=".price"andid="#total"are wrong. The.and#belong only in CSS selectors and inhref. - Spaces in an id.
id="order summary"is invalid; useorder-summary. - Reusing an id to style several elements. Use a class.
- Mixing up case.
class="Price"is not matched by.price. - Naming by looks.
big-red-textstops making sense after the next redesign.
Key points
- A
classgroups any number of elements; anidnames exactly one. - Names are case-sensitive, ids cannot contain spaces, and every name should start with a letter.
- One element can have many classes;
.a.bin CSS matches elements that have both. - ids are targets for jump links, labels, ARIA attributes, popovers and the
formattribute. - Style with classes, because id selectors are hard to override.
- JavaScript finds elements with
getElementById()andquerySelector(), and changes state withclassList.
Exercise
Build a "Train timetable" page with three trains as paragraphs. Give every train the class train, give delayed trains an extra class late (styled in red) and give one train an id. Add a link at the top that jumps to that train, and highlight it with :target. Finally, add a button that toggles a compact class on the <body>, where .compact .train uses a smaller font.
Show solution
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Train timetable</title>
<style>
.train { padding: 6px; border-bottom: 1px solid #ddd; }
.late { color: crimson; }
:target { background: lightyellow; }
.compact .train { font-size: 13px; }
</style>
</head>
<body>
<p><a href="#night-mail">Jump to the night train</a></p>
<p class="train">Lucknow to Kanpur, 07:10</p>
<p class="train late">Lucknow to Varanasi, 11:45 (delayed)</p>
<p class="train" id="night-mail">Lucknow to Delhi, 22:30</p>
<button type="button" id="size">Compact view</button>
<script>
document.getElementById("size").addEventListener("click", () => {
document.body.classList.toggle("compact");
});
</script>
</body>
</html>The descendant selector .compact .train only matches while the body has the compact class, so one classList.toggle() restyles every train at once.
Quick Quiz
1. Five product cards need the same border. What should they share?
A class can be shared by any number of elements; an id must be unique.
2. Which CSS selector matches only elements that have both the card and featured classes?
With no space between them, the two class selectors must match the same element.
3. Which attribute value correctly connects a label to <input id="city">?
Attributes such as for take the plain id; the # is only used in URLs and CSS selectors.
4. Why is document.querySelector("#2026-toppers") a problem?
HTML allows the id, but CSS selector syntax does not, so start names with a letter.
Learn HTML with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
