Styling Elements
Sometimes you need to change how an element looks at runtime: animate a value, position a tooltip under the cursor, or react to data that CSS alone can’t express. JavaScript gives you direct write access to an element’s inline styles through the style property, plus a read-only window into its final, rendered appearance via getComputedStyle. Knowing which one to reach for — and when to skip both in favor of a CSS class — is the difference between maintainable UI code and a tangle of inline rules.
The style property
Every element exposes a style object that maps to its inline style attribute. Setting a property here writes a declaration directly onto the element, which means it wins over almost everything in your stylesheets (short of !important). CSS property names become camelCase, since hyphens aren’t valid in JavaScript identifiers: background-color becomes backgroundColor, font-size becomes fontSize.
const box = document.querySelector("#box");
box.style.backgroundColor = "rebeccapurple";
box.style.fontSize = "1.5rem";
box.style.padding = "1rem 2rem";
box.style.borderRadius = "8px";
Values are always strings, and most length-based properties require their unit — box.style.width = "200px" works, but box.style.width = 200 is silently ignored.
Gotcha:
element.styleonly reflects styles set inline (via the attribute or via JavaScript). It does not see rules coming from your stylesheets. Readingbox.style.colorreturns an empty string unlesscolorwas set inline, even if the element is clearly colored by a CSS rule.
setProperty and CSS variables
The camelCase API can’t express custom properties (CSS variables) because --my-var isn’t a valid identifier. For those — and any time you want to set a property by its real CSS name — use setProperty, getPropertyValue, and removeProperty:
const card = document.querySelector(".card");
// Set a CSS custom property
card.style.setProperty("--accent", "#0ea5e9");
// Set a standard property, optionally with priority
card.style.setProperty("color", "white", "important");
// Read back an inline property
card.style.getPropertyValue("--accent"); // "#0ea5e9"
// Remove it
card.style.removeProperty("color");
Driving a CSS variable from JavaScript is a powerful pattern: you set one value in JS, and your stylesheet decides how to consume it. This keeps the heavy styling in CSS while letting JS supply just the dynamic number.
<style>
.swatch {
--hue: 200;
width: 120px;
height: 120px;
border-radius: 12px;
background: hsl(var(--hue) 80% 55%);
transition: background 0.15s ease;
}
input { width: 240px; }
</style>
<div class="swatch" id="swatch"></div>
<p><input type="range" id="hue" min="0" max="360" value="200" /></p>
<script>
const swatch = document.getElementById("swatch");
const slider = document.getElementById("hue");
slider.addEventListener("input", () => {
swatch.style.setProperty("--hue", slider.value);
});
</script>
Reading computed values with getComputedStyle
When you need to know what an element actually looks like — after stylesheets, inheritance, the cascade, and the browser’s defaults have all been applied — use window.getComputedStyle(element). It returns a read-only CSSStyleDeclaration of fully resolved values.
const el = document.querySelector("#box");
const styles = getComputedStyle(el);
styles.color; // e.g. "rgb(102, 51, 153)"
styles.fontSize; // e.g. "24px"
styles.display; // e.g. "flex"
// Custom properties resolve too
styles.getPropertyValue("--accent").trim();
A few things to keep in mind: computed values are resolved, so colors come back as rgb()/rgba() and relative units like em are converted to px. The object is live-ish but read-only — assigning to it throws in strict mode and is otherwise ignored. To change a value, write to element.style; to read the truth, read from getComputedStyle.
const el = document.querySelector("#box");
const lineHeightPx = parseFloat(getComputedStyle(el).lineHeight);
console.log(lineHeightPx);
Output:
28.8
Performance tip: Reading
getComputedStyle(or layout properties likeoffsetWidth) right after writing styles forces the browser to recalculate layout synchronously — a “layout thrash.” Batch your reads together, then your writes, instead of interleaving them in a loop.
style vs. getComputedStyle
| Aspect | element.style | getComputedStyle(element) |
|---|---|---|
| Direction | Read and write | Read-only |
| Source | Inline styles only | Full cascade (stylesheets + inline + inherited) |
| Returns | Inline value or "" | Resolved final value |
| Units | As you set them | Normalized (often px, rgb()) |
| Use it to | Apply dynamic styles | Inspect actual appearance |
Prefer class toggles for non-dynamic styling
Reach for inline styles only when the value is genuinely dynamic — a computed position, a slider-driven color, a width that depends on data. For everything else, define the look in CSS and flip a class with classList. This keeps presentation in your stylesheet, plays nicely with media queries and pseudo-classes, and avoids dozens of inline declarations that are hard to override.
<style>
.panel {
padding: 1rem 1.5rem;
border-radius: 8px;
font-family: system-ui, sans-serif;
background: #1e293b;
color: #cbd5e1;
transition: all 0.2s ease;
}
.panel.is-active {
background: #0ea5e9;
color: white;
box-shadow: 0 8px 24px rgba(14, 165, 233, 0.4);
}
</style>
<div class="panel" id="panel">Click me to toggle styling</div>
<script>
const panel = document.getElementById("panel");
panel.addEventListener("click", () => {
panel.classList.toggle("is-active");
});
</script>
The inline-style version of that effect would need you to set and reset six properties by hand on every click. The class version expresses the whole state in CSS and toggles it with a single line.
Best Practices
- Use
element.styleonly for truly dynamic values; express static looks as CSS classes you toggle. - Remember property names are camelCase (
backgroundColor), and usesetPropertyfor CSS variables and hyphenated names. - Always include units on length values — strings without them are ignored.
- Use
getComputedStyleto read resolved appearance; never expectelement.styleto reflect stylesheet rules. - Drive a CSS custom property from JS and let your stylesheet consume it, keeping styling logic in CSS.
- Batch DOM reads and writes to avoid forced synchronous layout (layout thrashing).
- Reset a single inline property by assigning
""(e.g.el.style.color = "") or callingremoveProperty.