Styling from JavaScript
Advanced · 18 min read · ▶ live playground · ✦ checkpoint
Changing text changes what the page says. Changing style changes what the page means: active, disabled, full, empty, close, far away. JavaScript can touch CSS directly, but the professional default is clear: use classes for state, and save inline values for numbers that really come from code.
Classes are the state switch
classList is an element's class controller. It gives you methods like add, remove, toggle, and contains so JavaScript can switch CSS states without rewriting the whole class string.
Think of classes as badges on an element. CSS decides what each badge means; JavaScript only pins on the right badge at the right moment.
The CSS owns the visual details: border color, background, weight. JavaScript owns the state choice: this card is boarding, not delayed. That split keeps your code readable because you do not have color values scattered through your JavaScript.
classList.toggle(name, force) is the sharp version of the same move. The second argument forces the class on for true and off for false, which is perfect when state comes from data.
Inline styles are for real dynamic values
An inline style is a style written directly on one element's style attribute. JavaScript can set it with element.style.propertyName, but that should not become your everyday styling tool.
Use inline styles when the value is genuinely dynamic: a progress percent, a measured pixel value, or a user-selected theme color. If the value is a named state like "selected" or "error", prefer a class.
That example uses a CSS custom property, a CSS variable whose name starts with --. JavaScript sets --completion, and CSS uses it in width: var(--completion, 0%).
Custom properties are useful because they keep the shape of the style in CSS while letting JavaScript supply one changing number. The code does not know how the meter is drawn. It only knows the value is 72%.
dataset stores small element facts
A data-* attribute is a custom HTML attribute for small app-specific facts, like data-plan="pro" or data-count="3". dataset is the JavaScript object that reads and writes those attributes.
Attribute names convert to camelCase:
data-planbecomeselement.dataset.plandata-player-idbecomeselement.dataset.playerId
Use dataset like a sticky note on one element, not like a database. It is good for small state that belongs to that element and can help CSS or later event code understand it.
Every dataset value is a string because HTML attributes are text. If you need a number for math, convert it with Number(...) before calculating.
Measure after layout
getBoundingClientRect() measures an element after layout and returns a DOMRect, an object with viewport-relative position and size fields like width, height, top, and left. Viewport-relative means the numbers are measured from the visible browser window, not from the whole document file.
Measurement is for questions CSS cannot answer alone: "how wide did this label actually render?" or "is this card taller than its container?" It is a read from the finished layout.
The rounded widths are stable because the CSS sets fixed widths. On real pages, font loading, responsive layout, and viewport size can change measurements, so measure at the moment you need the answer.
Other measurement tools exist, but they ask slightly different questions: offsetWidth gives a rounded layout width, clientWidth gives inner width without borders, and scrollWidth tells you how wide the content wants to be. Start with getBoundingClientRect() when you need the element's current box in the viewport.
The decision rule
When JavaScript changes presentation, choose the smallest honest tool:
- Use
classListfor named states: selected, hidden, expanded, invalid. - Use inline styles or custom properties for values that come from data or measurement.
- Use
datasetfor small element-specific facts, especially facts CSS or later event code can read. - Use measurement when you need the layout the browser actually produced.
You now have the full DOM toolkit for static scripts: find nodes, change nodes, style states, and measure layout. Next, those changes stop being automatic and start responding to people: Section 15 turns clicks, keys, and form input into page behavior.
Checkpoint
Answer all three to mark this lesson complete