Classes & IDs

HTML · Lesson 7 of 44 8 min read Updated

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?

classid
Meaning"This element belongs to a group""This is the one element called..."
How many elements can share itAny numberExactly one per page
Values per elementSeveral, separated by spacesOne
CSS selector.price#checkout
Typical jobsStyling, marking a state such as selectedJump 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 id must be unique on the page, must have at least one character and must not contain spaces.
  • A class value is a list of names separated by spaces. Each name can be anything without a space.
  • Both are case-sensitive: Price, price and PRICE are 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. notice stays true after a redesign; red-box becomes a lie the day the box turns blue.
  • Keep names short but clear: btn-primary is fine, b1 is 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.

HTMLTry it yourself
<!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.

FeatureHow 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 readersaria-describedby="email-hint"
Suggestions list for an input<input list="cities">
Button that opens a popoverpopovertarget="menu"
Control placed outside its formform="signup"

Notice that only the link uses a #. All the other attributes take the plain id.

HTMLTry it yourself
<!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:

CSS
.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.

CodeWhat 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.

HTMLTry it yourself
<!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" and id="#total" are wrong. The . and # belong only in CSS selectors and in href.
  • Spaces in an id. id="order summary" is invalid; use order-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-text stops making sense after the next redesign.

Key points

  • A class groups any number of elements; an id names 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.b in CSS matches elements that have both.
  • ids are targets for jump links, labels, ARIA attributes, popovers and the form attribute.
  • Style with classes, because id selectors are hard to override.
  • JavaScript finds elements with getElementById() and querySelector(), and changes state with classList.

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
HTML
<!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?

2. Which CSS selector matches only elements that have both the card and featured classes?

3. Which attribute value correctly connects a label to <input id="city">?

4. Why is document.querySelector("#2026-toppers") a problem?

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