HTML Fundamentals & Advanced Structures
From the I want notes on jQuery, html and mysql to prepare for an interview in 2 hours. Advanced hardness. Make each a topic curriculum
HTML Fundamentals & Advanced Structures
TL;DR
You'll walk into the interview able to explain how a browser turns raw HTML bytes into a rendered page, why semantic tags matter beyond "cleaner code," and how native form validation actually works under the hood. You'll also be able to write accessible, production-grade markup on a whiteboard without reaching for <div> as a default. That's the difference between "knows HTML" and "understands HTML."
1. The Mental Model
HTML isn't a styling language — it's a data structure describing meaning, and the browser, screen readers, and search engines all read that meaning to decide what to do. Every tag you choose is a signal you're sending to machines that can't see pixels. Get the structure right and accessibility, SEO, and CSS hooks come almost for free. HTML is the API you expose to every non-human consumer of your page.
2. The Core Material
2.1 Semantic HTML & the Accessibility Tree

Photo by Pixabay on Pexels
A <div> tells the browser nothing. A <nav>, <main>, or <button> tells it exactly what role that element plays, and the browser builds a second tree alongside the DOM — the accessibility tree — from those semantics. Screen readers navigate that tree, not your visual layout. This is why a <div onclick="..."> styled to look like a button is a real bug: it has no keyboard focus, no role="button", no Enter/Space activation, and shows up as nothing to assistive tech.
<header>
<nav aria-label="Primary">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
</ul>
</nav>
</header>
<main>
<article>
<h1>Q3 Earnings Report</h1>
<section aria-labelledby="summary-heading">
<h2 id="summary-heading">Summary</h2>
<p>Revenue grew 12% year over year.</p>
</section>
</article>
<aside aria-label="Related links">...</aside>
</main>
<footer>© 2024 Acme Corp</footer>
Key interview facts:
- Each page should have exactly one <h1>, and heading levels shouldn't skip (h1 → h3 with no h2 breaks the outline screen readers rely on).
- <section> requires an accessible name (via aria-labelledby or aria-label) to register as a landmark — otherwise it's just a styling hook.
- Native elements (<button>, <input>, <select>) come with keyboard behavior, focus states, and ARIA roles built in for free. Re-implementing a <button> with a <div> means you now own all of that yourself.
2.2 The Parsing Pipeline: Bytes → DOM → Render

Photo by Markus Spiske on Pexels
This is the classic "explain what happens when you load a page" question. The browser doesn't wait for the whole HTML file — it streams bytes through a tokenizer, builds DOM nodes incrementally, and starts rendering before the full document arrives.
flowchart LR
A["Raw HTML bytes"] --> B["Tokenizer"]
B --> C["Tree construction (DOM)"]
D["CSS bytes"] --> E["CSSOM"]
C --> F{"Script tag encountered?"}
F -- "Plain <script src>" --> G["Parser blocks: fetch + execute JS"]
F -- "async" --> H["Fetch in parallel, execute ASAP, may reorder"]
F -- "defer" --> I["Fetch in parallel, execute after DOM complete, in order"]
G --> C
C --> J["Render Tree = DOM + CSSOM"]
E --> J
J --> K["Layout (geometry)"]
K --> L["Paint"]
L --> M["Composite (GPU layers)"]
The critical detail: a plain <script> tag blocks HTML parsing entirely until it downloads and executes, because the script might call document.write() and mutate the tree. That's why the old advice was "put scripts at the bottom of <body>" — and why async/defer exist now to avoid that block without moving the tag.
async: downloads in parallel, executes the instant it's ready — order not guaranteed, can interrupt parsing.defer: downloads in parallel, executes only after parsing finishes, in document order. This is almost always what you want for app scripts.- CSS never blocks parsing of the DOM, but it does block rendering — the browser won't paint until it has the CSSOM, because painting half-styled content is worse than a blank flash.
2.3 Forms & the Constraint Validation API

Photo by Kindel Media on Pexels
Forms are where "I know HTML" gets tested for real, because native validation is powerful and most engineers reinvent it in JS unnecessarily.
<form id="signup" novalidate>
<label for="email">Email</label>
<input type="email" id="email" name="email" required
pattern=".+@company\.com" />
<span class="error" aria-live="polite"></span>
<label for="age">Age</label>
<input type="number" id="age" name="age" min="18" max="99" required />
<button type="submit">Sign up</button>
</form>
const form = document.getElementById('signup');
const email = document.getElementById('email');
form.addEventListener('submit', (e) => {
if (!form.checkValidity()) {
e.preventDefault();
if (email.validity.patternMismatch) {
email.setCustomValidity('Must be a company.com address');
} else {
email.setCustomValidity('');
}
form.reportValidity();
}
});
The ValidityState object (email.validity) exposes booleans like valueMissing, typeMismatch, patternMismatch, rangeUnderflow — you rarely need to hand-roll regex checks in JS when the browser already computed this. novalidate on the <form> disables the browser's default popup bubbles so you can render your own error UI while still using its validation logic. FormData is the modern way to read submitted values without manually querying every input:
form.addEventListener('submit', (e) => {
e.preventDefault();
const data = new FormData(form);
console.log(Object.fromEntries(data.entries()));
// { email: "a@company.com", age: "24" }
});
3. Worked Example
Task: Build an accessible signup form that validates a username is 3–15 characters, alphanumeric only, and shows a live error message — no external libraries, pure HTML + JS.
<form id="signup-form" novalidate>
<div class="field">
<label for="username">Username</label>
<input
type="text"
id="username"
name="username"
required
minlength="3"
maxlength="15"
pattern="[A-Za-z0-9]+"
aria-describedby="username-error"
/>
<span id="username-error" role="alert" class="error"></span>
</div>
<button type="submit">Create account</button>
</form>
const form = document.getElementById('signup-form');
const username = document.getElementById('username');
const errorEl = document.getElementById('username-error');
function validateUsername() {
username.setCustomValidity(''); // reset before re-checking
if (username.validity.patternMismatch) {
username.setCustomValidity('Letters and numbers only, no symbols');
} else if (username.validity.tooShort) {
username.setCustomValidity('Needs at least 3 characters');
} else if (username.validity.valueMissing) {
username.setCustomValidity('Username is required');
}
errorEl.textContent = username.validationMessage;
}
username.addEventListener('input', validateUsername);
form.addEventListener('submit', (e) => {
validateUsername();
if (!form.checkValidity()) {
e.preventDefault();
username.focus();
return;
}
const data = Object.fromEntries(new FormData(form).entries());
console.log('Submitting:', data);
});
Walk through what happens on a keystroke of "a!":
- The
inputevent fires, callingvalidateUsername(). setCustomValidity('')clears any prior error so we get a fresh check.- The browser evaluates the
patternattribute against"a!"— it fails because!isn't in[A-Za-z0-9]+, sousername.validity.patternMismatchistrue. - We call
setCustomValidity(...)with our own message, which overridescheckValidity()— the form will now report invalid even though nothing else is wrong. errorEl.textContentis set tousername.validationMessage, which is exactly the string we passed tosetCustomValidity. BecauseerrorElhasrole="alert", screen readers announce it immediately without the user needing to tab to it.- On submit, if the user fixes it to
"abc123", all validity flags clear,checkValidity()returnstrue, andFormDatacollects{ username: "abc123" }for a real AJAX call.
This is the pattern interviewers want to see: native HTML validation doing the heavy lifting, JS only supplying custom messages and wiring accessibility — not reimplementing regex checks by hand in onsubmit.
4. Production Pitfalls & Best Practices
4.1 Real-World Best Practices

Photo by Following NYC on Pexels
- Use
<button type="button">explicitly inside forms for non-submit actions — the defaulttypefor a<button>inside a<form>issubmit, a classic accidental-form-submission bug. - Always pair
<label>withfor/id, not just placeholder text — placeholders disappear on input and aren't reliably read by all screen readers. - One
<h1>per page, and treat headings as an outline, not a font-size tool — use CSS for size, headings for hierarchy. - Prefer
deferover inline scripts at the bottom of<body>— it keeps script tags in<head>(easier to find) without blocking the parser. - Use
<template>for client-rendered repeated markup instead of string-concatenating HTML — it's parsed once, inert until cloned, and avoids injection risk from string building. - Set
langon<html>— screen readers use it to pick pronunciation rules; forgetting it is a top accessibility audit failure. - Validate on both client and server — client-side
pattern/requiredis UX, never security; acurlrequest bypasses all of it.
4.2 Common Bugs & Anti-Patterns
Bug 1: Clickable div instead of button
<!-- BAD -->
<div class="btn" onclick="submitForm()">Submit</div>
<!-- FIXED -->
<button type="submit" class="btn">Submit</button>
Bug 2: Multiple labels pointing to nothing
<!-- BAD: label not linked, screen reader announces nothing -->
<label>Email</label>
<input type="email" name="email">
<!-- FIXED -->
<label for="email">Email</label>
<input type="email" id="email" name="email">
**Bug 3: Blocking render with synchronous scrip
Frequently asked about HTML Fundamentals & Advanced Structures
More from I want notes on jQuery, html and mysql to prepare for an interview in 2 hours. Advanced hardness. Make each a topic
Get the full I want notes on jQuery, html and mysql to prepare for an interview in 2 hours. Advanced hardness. Make each a topic curriculum
Clone the complete plan to your dashboard for unlimited AI-generated notes, practice quizzes, and a personalised revision schedule.
Create Free Account