Attributes and Classes

Learn how to read, set, and remove HTML attributes with JavaScript, and how to manage an element's CSS classes using the classList API.

Beyond text content, elements carry attributes (like href, src, disabled, and data-* custom attributes) and CSS classes that control their appearance and behavior. JavaScript provides dedicated methods for working with both cleanly, without resorting to manual string manipulation.

Reading and writing attributes

element.getAttribute(name) returns the current value of any HTML attribute as a string, or null if the attribute isn't present. element.setAttribute(name, value) sets an attribute to a given value, creating it if it doesn't already exist, or overwriting it if it does.

element.hasAttribute(name) returns a boolean telling you whether the attribute exists at all (useful for attributes like disabled or checked, where merely being present matters more than its value), and element.removeAttribute(name) deletes the attribute entirely.

Attributes vs. properties

Many HTML attributes are also directly accessible as JavaScript properties on the element object — for example element.id, element.src, and element.href mirror the id, src, and href attributes. For simple, well-known attributes, using the property directly (img.src = "photo.jpg") is often more convenient than calling setAttribute.

However, getAttribute/setAttribute remain essential for custom attributes that have no matching JavaScript property, especially data-* attributes (though these also have a convenient element.dataset API), and for cases where you specifically need the exact string value as written in the HTML rather than a browser-normalized version.

The classList API

element.classList is a special object representing the element's class attribute as a live, structured set rather than a single space-separated string, which makes adding, removing, and checking individual classes far cleaner than manipulating className as raw text.

This is the standard, modern way to control an element's appearance dynamically — toggling a .hidden class to show/hide something, adding an .active class to highlight the current tab, or adding an .error class when form validation fails.

add, remove, toggle, contains

classList.add(className) adds a class (doing nothing if it's already present — no duplicate classes), and classList.remove(className) removes it (doing nothing if it isn't present, so it's always safe to call).

classList.toggle(className) adds the class if it's absent and removes it if it's present, flipping its state each call — extremely useful for things like a menu that opens and closes on each click. classList.toggle(className, force) takes an optional second boolean argument that forces the class to be added (true) or removed (false) rather than toggling, which is handy when you want to set an exact known state.

classList.contains(className) returns a boolean telling you whether the class is currently present, commonly used in an if statement to branch behavior based on current state.

Attribute and class methods

getAttribute always returns a string (or null); it never returns a number or boolean directly, even for attributes that look numeric. classList.add()/remove() can each accept multiple class names in one call, e.g. classList.add("a", "b"). classList.toggle(name, force) is the cleanest way to set a class to a specific known state rather than blindly flipping it.

const link = document.querySelector("a");

link.getAttribute("href");            // reads the href value
link.setAttribute("target", "_blank"); // sets/creates an attribute
link.hasAttribute("download");         // true/false
link.removeAttribute("target");        // removes it

const box = document.querySelector(".box");
box.classList.add("active");
box.classList.remove("hidden");
box.classList.toggle("selected");
box.classList.toggle("open", true);    // force-add
box.classList.contains("active");      // true

Code Examples

Reads an existing attribute (src), sets a new one (alt), and confirms it was added by checking hasAttribute. Expected result: logo.png (or whatever the src value is) true image.setAttribute("alt", "SampleApp logo") creates the alt attribute if it wasn't already there.

A very common real pattern: clicking a button toggles a CSS class that a stylesheet uses to show/hide (or animate open/closed) a menu, without JavaScript needing to know anything about the actual CSS styling rules. Expected result: Clicking #menu-toggle alternately adds and removes the "open" class on #menu, which CSS uses to show or hide it.

menu.classList.toggle("open") adds "open" if it's missing, or removes it if it's present, flipping the menu's visible state on each click.

Combines classList.toggle with a force argument to set two mutually exclusive classes to an exact known state (rather than blindly flipping them), and sets an accessibility attribute (aria-invalid) alongside the visual styling classes. Expected result: For a valid email: classes become ["valid"], aria-invalid="false". For an invalid one: classes become ["error"], aria-invalid="true". Using the two-argument form of toggle() avoids a common bug where calling classList.add/remove separately could leave both or neither class applied if the logic isn't carefully ordered.

input.classList.toggle("error", !isValid) forces "error" on when isValid is false, and off when isValid is true — an exact state, not a flip.

const image = document.querySelector("#logo");
console.log(image.getAttribute("src"));
image.setAttribute("alt", "SampleApp logo");
console.log(image.hasAttribute("alt"));
const menuButton = document.querySelector("#menu-toggle");
const menu = document.querySelector("#menu");

menuButton.addEventListener("click", () => {
  menu.classList.toggle("open");
});
function setFieldValidity(input, isValid) {
  input.classList.toggle("error", !isValid);
  input.classList.toggle("valid", isValid);
  input.setAttribute("aria-invalid", String(!isValid));
}

const emailInput = document.querySelector("#email");
const isValidEmail = emailInput.value.includes("@");
setFieldValidity(emailInput, isValidEmail);

Important Rules

getAttribute()/setAttribute() work with any HTML attribute by name and always deal in strings.

Many common attributes (id, src, href, value, checked) also exist as direct JavaScript properties, which is often more convenient than the attribute methods.

classList.add/remove are safe to call even if the class is already present/absent — they simply do nothing extra in that case.

classList.toggle(name, force) is the reliable way to set a class to a specific true/false state rather than flipping it blindly.

hasAttribute() checks presence (a boolean); getAttribute() retrieves the value (a string or null) — use the right one for the question you're asking.

Where this shows up

Nearly every interactive UI pattern relies on this: toggling a dark-mode class on <body>, marking the active tab or nav link, showing validation error states on form fields, disabling a submit button via the disabled attribute while a request is in flight, and driving CSS animations (like a modal fade-in) purely by adding/removing a class.

element.className = element.className + " active";

Manually concatenating onto className as a raw string is error-prone (risk of double spaces, duplicate classes, or missing a leading space) and doesn't check whether the class is already present. classList.add() handles all of this correctly and safely.

if (element.classList.toggle("active")) { /* assuming it's now active */ } element.classList.toggle("active", true); // explicitly force it on // or check afterward: element.classList.contains("active") toggle() without a force argument flips state unpredictably depending on what the class currently is, which can be confusing when you actually want a guaranteed specific outcome. Its return value does tell you the new state, but for clarity, prefer the two-argument force form when you know the exact state you want.

[Multiple Choice] Which classList method adds a class if it's missing and removes it if it's already present? A. add() B. remove() C. toggle() D. contains()

C. toggle() — toggle() flips the class's presence: it adds the class if it's currently absent, and removes it if it's currently present. add() and remove() are one-directional, and contains() only checks, without changing, anything.

[True / False] Calling element.classList.remove("foo") when the element does not currently have the class "foo" will throw an error. A. True B. False

B. False — False. classList.remove() is always safe to call — if the specified class isn't present, it simply does nothing, with no error thrown.

Write a function toggleDarkMode() that toggles a class named "dark" on document.body, and also updates a button with id "theme-btn" so its text reads "Light Mode" when dark mode is on, and "Dark Mode" when it's off.

function toggleDarkMode() { const isDark = document.body.classList.toggle("dark"); const btn = document.querySelector("#theme-btn"); btn.textContent = isDark ? "Light Mode": "Dark Mode"; } classList.toggle() returns true if the class ends up present after toggling, which you can use to decide the button's new text.