Changing CSS Styles with JavaScript DOM Methods

Learn how to change CSS styles dynamically with JavaScript. Master inline styles, classList, getComputedStyle, and CSS custom properties for responsive, interactive web pages.

JavaScriptbeginner
10 min read

Dynamic styling is the foundation of interactive web pages. Dropdown menus, dark mode toggles, animation triggers, form validation indicators: they all work by changing CSS through JavaScript. This guide covers every approach from inline styles to CSS custom properties, with clear examples showing when to use each technique.

Method 1: The style Property (Inline Styles)

Every DOM element has a style property that lets you read and write individual CSS properties directly. These become inline styles on the element.

javascriptjavascript
const box = document.getElementById("box");
 
// Set individual CSS properties
box.style.backgroundColor = "blue";
box.style.width = "200px";
box.style.height = "200px";
box.style.borderRadius = "8px";
box.style.transition = "all 0.3s ease";

CSS Property Name Conversion

CSS properties use kebab-case (background-color). JavaScript uses camelCase (backgroundColor):

javascriptjavascript
const element = document.querySelector(".card");
 
// CSS property โ†’ JavaScript property
element.style.backgroundColor = "#f0f0f0";  // background-color
element.style.fontSize = "16px";             // font-size
element.style.marginTop = "20px";            // margin-top
element.style.borderBottomWidth = "2px";     // border-bottom-width
element.style.zIndex = "10";                 // z-index
element.style.boxShadow = "0 2px 4px rgba(0,0,0,0.1)"; // box-shadow

You can also use bracket notation with the original CSS property names:

javascriptjavascript
element.style["background-color"] = "#f0f0f0";
element.style["font-size"] = "16px";
element.style["margin-top"] = "20px";
CSS PropertyJavaScript PropertyBracket Notation
background-colorbackgroundColorstyle["background-color"]
font-sizefontSizestyle["font-size"]
border-radiusborderRadiusstyle["border-radius"]
z-indexzIndexstyle["z-index"]
max-widthmaxWidthstyle["max-width"]
line-heightlineHeightstyle["line-height"]

Reading Inline Styles

The style property only reads inline styles that were set via JavaScript or the HTML style attribute. It does NOT read styles from CSS files.

javascriptjavascript
// HTML: <div id="box" style="width: 100px;"></div>
// CSS file: #box { height: 200px; color: red; }
 
const box = document.getElementById("box");
 
console.log(box.style.width);  // "100px" (inline style exists)
console.log(box.style.height); // "" (empty! set in CSS file, not inline)
console.log(box.style.color);  // "" (empty! set in CSS file, not inline)

Removing Inline Styles

javascriptjavascript
// Remove a single style property
element.style.backgroundColor = ""; // Resets to CSS/default value
 
// Remove all inline styles
element.style.cssText = "";
 
// Or use removeProperty
element.style.removeProperty("background-color");

Setting Multiple Styles with cssText

javascriptjavascript
const card = document.querySelector(".card");
 
// Set multiple properties at once (overwrites ALL existing inline styles)
card.style.cssText = `
  background-color: white;
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
`;
 
// Append to existing inline styles (preserves existing)
card.style.cssText += "margin-top: 20px;";

Method 2: getComputedStyle (Reading Applied Styles)

To read the actual computed styles (from CSS files, browser defaults, and inline), use getComputedStyle:

javascriptjavascript
const box = document.getElementById("box");
 
// Get ALL computed styles
const styles = getComputedStyle(box);
 
// Read specific properties (always returns resolved values)
console.log(styles.width);           // "200px" (computed pixel value)
console.log(styles.backgroundColor); // "rgb(255, 0, 0)" (computed color)
console.log(styles.fontSize);        // "16px"
console.log(styles.display);         // "block"
console.log(styles.margin);          // "10px" (shorthand may vary by browser)

Computed Style vs Inline Style

javascriptjavascript
// CSS: .box { width: 50%; padding: 1em; color: var(--primary); }
const box = document.querySelector(".box");
 
// Inline style returns what you SET (empty if not set inline)
console.log(box.style.width);   // "" (not set inline)
console.log(box.style.padding); // "" (not set inline)
 
// Computed style returns what the browser CALCULATED
const computed = getComputedStyle(box);
console.log(computed.width);   // "312px" (50% resolved to pixels)
console.log(computed.padding); // "16px" (1em resolved to pixels)
console.log(computed.color);   // "rgb(59, 130, 246)" (variable resolved)
Read MethodReturnsIncludes CSS filesIncludes defaultsResolves units
element.style.propInline value or ""NoNoNo
getComputedStyle(el).propFinal computed valueYesYesYes (px, rgb, etc.)

Method 3: classList (CSS Class Toggling)

The most maintainable approach to dynamic styling is toggling CSS classes rather than setting inline styles. Keep your styles in CSS and use JavaScript only to add or remove classes.

javascriptjavascript
const button = document.querySelector(".menu-toggle");
const nav = document.querySelector(".mobile-nav");
 
button.addEventListener("click", () => {
  nav.classList.toggle("open");
});
csscss
/* CSS handles all the styling */
.mobile-nav {
  transform: translateX(-100%);
  transition: transform 0.3s ease;
}
 
.mobile-nav.open {
  transform: translateX(0);
}

classList Methods

javascriptjavascript
const element = document.querySelector(".card");
 
// Add one or more classes
element.classList.add("active");
element.classList.add("highlighted", "expanded"); // Multiple at once
 
// Remove one or more classes
element.classList.remove("active");
element.classList.remove("highlighted", "expanded");
 
// Toggle a class (add if missing, remove if present)
element.classList.toggle("visible");
 
// Toggle with force parameter
element.classList.toggle("dark", true);  // Always add
element.classList.toggle("dark", false); // Always remove
 
// Check if class exists
if (element.classList.contains("active")) {
  console.log("Element is active");
}
 
// Replace one class with another
element.classList.replace("old-class", "new-class");

Why classList Is Better Than Inline Styles

javascriptjavascript
// APPROACH 1: Inline styles (hard to maintain)
function showError(input) {
  input.style.borderColor = "red";
  input.style.backgroundColor = "#fff5f5";
  input.style.boxShadow = "0 0 0 3px rgba(255, 0, 0, 0.1)";
}
 
function hideError(input) {
  input.style.borderColor = "";
  input.style.backgroundColor = "";
  input.style.boxShadow = "";
}
 
// APPROACH 2: CSS classes (clean, maintainable)
function showError(input) {
  input.classList.add("input-error");
}
 
function hideError(input) {
  input.classList.remove("input-error");
}
CriteriaInline Styles (element.style)CSS Classes (classList)
Separation of concernsMixes JS and CSSKeeps styles in CSS
SpecificityHigh (overrides most CSS)Normal (follows cascade)
MaintainabilityHard to updateEasy to update in CSS
ReusabilityMust copy code for each elementApply class to any element
Media queriesNot possibleFully supported
Transitions/animationsMust set each propertyDefine once in CSS
PerformanceTriggers individual reflowsSingle reflow for class change

Method 4: CSS Custom Properties (Variables)

CSS custom properties (variables) bridge the gap between JavaScript and CSS beautifully. Set a variable in JavaScript, and CSS handles the rendering:

javascriptjavascript
// Set a CSS variable on the root element
document.documentElement.style.setProperty("--primary-color", "#3b82f6");
document.documentElement.style.setProperty("--font-size-base", "16px");
document.documentElement.style.setProperty("--sidebar-width", "280px");
csscss
/* CSS uses the variables */
.button {
  background-color: var(--primary-color);
  font-size: var(--font-size-base);
}
 
.sidebar {
  width: var(--sidebar-width);
}

Dark Mode Toggle with CSS Variables

javascriptjavascript
function toggleDarkMode() {
  const root = document.documentElement;
  const isDark = root.classList.toggle("dark");
 
  if (isDark) {
    root.style.setProperty("--bg-color", "#1a1a2e");
    root.style.setProperty("--text-color", "#e0e0e0");
    root.style.setProperty("--card-bg", "#16213e");
    root.style.setProperty("--border-color", "#2a2a4a");
  } else {
    root.style.setProperty("--bg-color", "#ffffff");
    root.style.setProperty("--text-color", "#1a1a1a");
    root.style.setProperty("--card-bg", "#f8f9fa");
    root.style.setProperty("--border-color", "#e0e0e0");
  }
 
  // Save preference
  localStorage.setItem("darkMode", isDark);
}
 
// Read a CSS variable value
const primaryColor = getComputedStyle(document.documentElement)
  .getPropertyValue("--primary-color")
  .trim();
console.log(primaryColor); // "#3b82f6"

Scoped CSS Variables

javascriptjavascript
// Set variables on specific elements (scoped, not global)
function setCardTheme(cardElement, color) {
  cardElement.style.setProperty("--card-accent", color);
}
 
// Each card can have a different accent color
const cards = document.querySelectorAll(".card");
const colors = ["#ef4444", "#22c55e", "#3b82f6", "#f59e0b"];
 
cards.forEach((card, index) => {
  setCardTheme(card, colors[index % colors.length]);
});
csscss
.card {
  border-left: 4px solid var(--card-accent, #ccc);
}
 
.card h3 {
  color: var(--card-accent, #333);
}

Method 5: Stylesheet Manipulation

For advanced cases, you can create and modify entire stylesheets from JavaScript:

javascriptjavascript
// Create a new stylesheet
const sheet = new CSSStyleSheet();
sheet.replaceSync(`
  .dynamic-card {
    background: white;
    border-radius: 8px;
    padding: 16px;
  }
  .dynamic-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  }
`);
 
// Adopt the stylesheet
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
 
// Modify rules later
sheet.insertRule(".dynamic-card.featured { border: 2px solid gold; }", sheet.cssRules.length);

Best Practices

1. Prefer CSS Classes Over Inline Styles

javascriptjavascript
// GOOD: Toggle a class
element.classList.toggle("expanded");
 
// AVOID: Set multiple inline properties
element.style.height = "auto";
element.style.opacity = "1";
element.style.overflow = "visible";

2. Use CSS Variables for Theming

javascriptjavascript
// GOOD: One variable change updates many elements
document.documentElement.style.setProperty("--accent", newColor);
 
// AVOID: Update each element individually
buttons.forEach(btn => { btn.style.backgroundColor = newColor; });
links.forEach(link => { link.style.color = newColor; });
headers.forEach(h => { h.style.borderColor = newColor; });

3. Batch Style Changes

javascriptjavascript
// SLOW: Multiple individual style changes trigger multiple reflows
element.style.width = "100px";
element.style.height = "100px";
element.style.margin = "10px";
element.style.padding = "5px";
 
// FAST: Single class toggle triggers one reflow
element.classList.add("compact");
 
// ALSO FAST: cssText sets all at once
element.style.cssText = "width: 100px; height: 100px; margin: 10px; padding: 5px;";

Common Mistakes to Avoid

Mistake 1: Forgetting Units

javascriptjavascript
// WRONG: No unit, style is ignored
element.style.width = 200;      // Does nothing
element.style.fontSize = 16;    // Does nothing
 
// CORRECT: Always include units
element.style.width = "200px";
element.style.fontSize = "16px";
 
// Exception: unitless properties
element.style.opacity = "0.5";  // No unit needed
element.style.zIndex = "10";    // No unit needed
element.style.lineHeight = "1.5"; // Unitless ratio is valid

Mistake 2: Reading Styles Before Browser Calculates Them

javascriptjavascript
// PROBLEM: Reading computed style immediately after setting it
element.style.width = "50%";
const width = getComputedStyle(element).width;
// May return the OLD value if browser hasn't recalculated yet
 
// SOLUTION: Force a reflow by reading a layout property
element.style.width = "50%";
element.offsetHeight; // Forces reflow
const width = getComputedStyle(element).width; // Now returns updated value

Mistake 3: Using className Instead of classList

javascriptjavascript
// DANGEROUS: Overwrites ALL existing classes
element.className = "active"; // Removes every other class!
 
// SAFE: Adds/removes without affecting other classes
element.classList.add("active");
element.classList.remove("active");

Real-World Example: Interactive Theme Customizer

javascriptjavascript
function createThemeCustomizer() {
  const root = document.documentElement;
 
  const controls = {
    primary: document.getElementById("color-primary"),
    background: document.getElementById("color-bg"),
    fontSize: document.getElementById("font-size"),
    borderRadius: document.getElementById("border-radius")
  };
 
  // Apply theme changes in real time
  function applyTheme() {
    root.style.setProperty("--primary", controls.primary.value);
    root.style.setProperty("--bg-color", controls.background.value);
    root.style.setProperty("--font-base", controls.fontSize.value + "px");
    root.style.setProperty("--radius", controls.borderRadius.value + "px");
  }
 
  // Listen for changes on all controls
  Object.values(controls).forEach(control => {
    control.addEventListener("input", applyTheme);
  });
 
  // Save theme to localStorage
  document.getElementById("save-theme").addEventListener("click", () => {
    const theme = {};
    Object.entries(controls).forEach(([key, control]) => {
      theme[key] = control.value;
    });
    localStorage.setItem("customTheme", JSON.stringify(theme));
 
    const status = document.getElementById("save-status");
    status.textContent = "Theme saved!";
    status.classList.add("visible");
 
    setTimeout(() => status.classList.remove("visible"), 2000);
  });
 
  // Load saved theme
  const saved = localStorage.getItem("customTheme");
  if (saved) {
    const theme = JSON.parse(saved);
    Object.entries(theme).forEach(([key, value]) => {
      if (controls[key]) controls[key].value = value;
    });
    applyTheme();
  }
}
 
createThemeCustomizer();
Rune AI

Rune AI

Key Insights

  • classList first: Toggle CSS classes as your default approach; keep styling logic in your CSS files
  • CSS variables for themes: Use setProperty("--var", value) to update many elements through a single variable change
  • Inline styles for dynamic values: Use element.style only for values that change frequently or cannot be predefined (drag positions, color pickers)
  • getComputedStyle for reading: The style property only reads inline styles; use getComputedStyle() to read the actual rendered values
  • Performance: Batch style changes with classList or cssText to avoid multiple reflows; never alternate reading and writing layout properties
RunePowered by Rune AI

Frequently Asked Questions

Should I use inline styles or CSS classes in JavaScript?

Prefer CSS classes (via `classList`) for most styling changes. They keep your styles in CSS files where they belong, support media queries and pseudo-classes, and are easier to maintain. Use inline styles only for truly dynamic values that change constantly, like positions during drag operations or colors from a user-controlled color picker.

How do I animate styles with JavaScript?

The best approach is to define CSS transitions or animations in your stylesheet, then toggle a class with JavaScript to trigger them. For more complex animations, use the Web Animations API (`element.animate()`) which gives you JavaScript control over keyframes and timing without inline style overhead.

What is the performance impact of changing styles with JavaScript?

Each style change can trigger a browser reflow (layout recalculation) and repaint. Batch changes together using `classList` (single class toggle), `cssText` (multiple properties at once), or CSS custom properties (one variable updates many elements). Avoid reading and writing layout properties alternately, as this causes "layout thrashing."

Can I use JavaScript to change styles in a CSS file?

Yes, through the CSSOM (CSS Object Model). You can access `document.styleSheets` to modify rules in existing stylesheets, or create new stylesheets with `new CSSStyleSheet()`. However, this is an advanced technique. For most cases, CSS custom properties or class toggling are simpler and more maintainable.

How do CSS custom properties differ from inline styles?

CSS custom properties cascade through the DOM like regular CSS, meaning child elements inherit them from parents. Inline styles only affect the specific element. Custom properties also work inside media queries, calc() expressions, and CSS transitions, while inline styles set via JavaScript cannot use these CSS features.

Conclusion

JavaScript provides multiple ways to change CSS, and choosing the right approach depends on the situation. Use classList for toggling predefined visual states like "active," "expanded," or "dark." Use CSS custom properties for theme-wide changes where one variable controls many elements. Use the style property for truly dynamic values that cannot be predefined in CSS. Use getComputedStyle to read the final rendered values when you need to measure elements. The pattern that produces the cleanest, most maintainable code is keeping your styles in CSS and using JavaScript only to toggle classes or update variables.