HTML interview questions with model answers

70 questions written alongside the free HTML course, each with the answer an interviewer is listening for. 30 are below, spread from first principles to advanced; the rest are in the course.

What HTML interviews test

HTML interviews check whether you choose elements by meaning: document structure and the head, semantic landmarks, forms and native validation, tables, accessible names and ARIA, and how the browser parses and loads a page.

  1. 1. What happens between typing a URL and seeing a page?

    DNS resolves the domain to an IP address; the browser opens a TLS-secured connection and sends an HTTP request; the server responds with headers and an HTML body; the browser parses that text into the DOM, fetches the resources the document references (CSS, images, scripts), applies styles, runs scripts, and renders. The key insight interviewers look for: HTML arrives as plain text, and the DOM — a tree built by the parser — is what everything else operates on.

    From the lesson How the Web Works and Where HTML Fits

  2. 2. What does the browser do with <p><ul><li>x</li></ul></p>?

    A ul is not phrasing content, so it cannot live inside p. The parser closes the paragraph implicitly when the ul starts, producing a p and a ul as siblings, and the trailing closing-p tag matches nothing (a parse error, recovered by ignoring it or creating an empty p depending on context). The page renders, but the author’s intended containment never existed — which is exactly why validity matters even though browsers do not enforce it.

    From the lesson Elements, Tags, Attributes and Nesting

  3. 3. em versus strong versus i versus b — how do you choose?

    em is linguistic stress that changes how the sentence reads; strong is importance or urgency independent of stress; i is an alternate voice or register (terms, titles, foreign phrases) with no added weight; b is visual attention with no semantic claim at all. The practical test: could a screen reader legitimately change its delivery for this? Stress (em) and seriousness (strong) yes; i and b are typographic conventions the reader mostly passes through.

    From the lesson Text-Level Semantics: Emphasis, Importance and Edits

  4. 4. Your image renders locally but 404s in production. Walk through the diagnosis.

    First compare case exactly — dev machines on Windows/macOS are usually case-insensitive while Linux servers are not; Logo.png versus logo.png is the classic. Then check the path form: a root-relative /images/... breaks if production serves the site under a subpath. Then encoding — spaces and unicode in filenames. Then whether the file actually deployed. The general lesson: local success proves resolution on one filesystem, not on the server’s.

    From the lesson Files, Folders and Paths

  5. 5. How do you decide what goes in an alt attribute?

    By function, not appearance. Ask what information the image contributes: convey exactly that ("signups doubled to 8,100", not "a chart"). If it contributes none — decoration, or text repeats it — use alt="" so assistive tech skips it; omitting the attribute instead makes readers announce the filename. If the image is inside a link, describe the destination. If it contains text, the text goes in the alt. And never prefix "image of" — the role is already announced.

    From the lesson Images: src, alt and Layout Stability

  6. 6. Is there anything wrong with using lots of divs?

    Not per se — layout scaffolding is div’s legitimate job, and complex CSS often needs wrappers. The failure mode is divs replacing meaning: div-with-heading-class instead of h2, div-with-onclick instead of a or button. The audit: strip the CSS and read the page — if the structure disappears with the stylesheet, semantics were never there. Divs should be removable without any meaning being lost.

    From the lesson div, span and the Discipline of Meaning Nothing

  7. 7. srcset with w descriptors versus picture — when is each correct?

    w-descriptor srcset when every candidate is the same image at different resolutions: the browser picks freely using sizes, density and its own heuristics, and may legitimately vary. picture when candidates are meaningfully different — another crop (media) or another format (type) — so the choice must follow your stated conditions, first match wins. The rule of thumb: same picture, srcset; different picture, picture.

    From the lesson Responsive Images: srcset, sizes and picture

  8. 8. What does the sandbox attribute actually do, and which token combination undoes it?

    It applies a deny-by-default policy to the framed document: scripts, forms, popups, top navigation, pointer lock all off, and the content is assigned a unique opaque origin so it cannot use even its own site’s credentials. Tokens re-enable capabilities individually. The undoing pair is allow-scripts with allow-same-origin on same-origin content: the document can then run script under its true origin, reach its embedder, and remove the sandbox attribute itself — so that pair is reserved for content you would trust unframed.

    From the lesson iframe, embed, object and the Sandbox

  9. 9. Why does injected RTL text scramble surrounding punctuation, and what is the fix?

    The Unicode bidirectional algorithm assigns neutral characters — spaces, dashes, digits’ neighbors, punctuation — to an adjacent strong run. An injected Arabic or Hebrew name is a strong RTL run, so the dash and score that follow it visually attach to the name instead of the sentence. bdi isolates the injected run: internally it lays out RTL, externally it counts as a neutral island, so the template’s own layout survives any input. The rule: every slot printing user text of unknown script gets bdi.

    From the lesson International Text: lang, dir, bdi and ruby

  10. 10. Why is placeholder-only labeling an accessibility failure, and what is placeholder actually for?

    Four compounding failures: the hint disappears once typing starts (users mid-form forget what the field was); default contrast fails WCAG; some assistive tech does not announce placeholder as a name; and cognitive-load research shows users re-clearing fields to re-read hints. placeholder’s legitimate job is a format example beneath a persistent label — "DD/MM/YYYY", "name@example.com" — never the name itself.

    From the lesson Labels, Text Input States and Autofill

  11. 11. What makes radio buttons mutually exclusive, and what are the two classic radio-group bugs?

    The shared name attribute — nothing visual, nothing positional. The group submits one pair: the name plus the checked member’s value. Bug one: unique names per radio, making everything selectable and nothing deselectable (radios cannot be unchecked by clicking again). Bug two: no checked default combined with required-less markup, so the group can submit nothing at all — servers then see the field vanish rather than arrive empty.

    From the lesson Checkboxes, Radios, select and datalist

  12. 12. A user swears they attached a file but the server has nothing. The form validates. What happened?

    Almost certainly the form lacks enctype="multipart/form-data" (or uses method="get"): the default urlencoded encoding submits only the filename as text, so the request succeeds, the ticket is created, and the file bytes never leave the machine. It validates because enctype is optional — the requirement is contractual, not grammatical. Fix the form, then check the server also enforces size and type limits, because accept filters the picker, not the request.

    From the lesson textarea, File Uploads and enctype

  13. 13. progress or meter for a password-strength indicator, and why?

    meter. Strength is a level on a known scale with good and bad zones — low/high/optimum map perfectly to weak/okay/strong — not a task marching to completion; announcing “40% complete” about a password would be nonsense. progress is reserved for work heading to done: uploads, installs, multi-step flows. The tell in an interview: if omitting the value would honestly mean “unknown duration” (indeterminate), it is progress; if omitting it just means “no reading”, it is meter.

    From the lesson output, progress and meter

  14. 14. Walk me through a minimal correct head and why each line is there.

    Doctype above it for standards mode; html lang for language. Then in order: meta charset utf-8 — decoding, first and once, inside 1024 bytes; meta viewport width=device-width, initial-scale=1 — real mobile layout, never user-scalable=no (the checker warns, low-vision users pinch-zoom); title — the only required head element, feeding tab, bookmark, screen-reader announcement and search result; meta description — the snippet, an ad, not a ranking factor; an icon link. Everything else — base, theme-color, social cards, JSON-LD — is added when a consumer for it exists.

    From the lesson The head: Metadata that Runs the Page

  15. 15. defer vs async — and why does a bare script src block at all?

    A bare external script halts the parser to fetch and run, because it might document.write into the byte stream — a legacy contract the parser must honor. defer opts out: fetch in parallel, execute after parsing, preserving document order, so dependent files stay correct — the right default for site code, even in the head. async also fetches in parallel but executes on arrival in no guaranteed order — only for self-contained code like analytics. type="module" behaves like defer automatically and adds CORS fetching; nomodule serves the legacy twin. And src-plus-inline-content is a conformance error — browsers silently drop the inline part.

    From the lesson script: defer, async, module

  16. 16. A shared link shows the wrong image and yesterday’s title. The page is fixed. What do you check?

    Three layers. Markup: og:image must be an absolute https URL — relative paths silently fail; confirm og:title/og:description/og:url exist and use property= (not name=), with og:url matching the canonical. Cache: scrapers cache scrapes, so a fixed page keeps serving the old card until you force a re-scrape in the platform’s card debugger. Precedence: platform-specific tags like twitter:title override OG on their platform, so a stale override shows old data in one app while others look right. The HTML validator has no opinion on any of this — the card debuggers are the ground truth for the sharing layer.

    From the lesson Open Graph and Twitter Cards

  17. 17. The hero image paints late and the page jumps during load. Diagnose from markup alone.

    Late hero: check for loading="lazy" on it (the classic self-sabotage — lazy deprioritizes the LCP element), then whether it could be preloaded (link rel="preload" as="image") and priority-raised (fetchpriority="high"), and whether render-blocking scripts should be defer/module. Jumping: unsized media — img and iframe without width/height reserve no box, so each arrival reflows the page; fonts swapping also shift text, which CSS font-display owns, markup contributing the font preload. The framing that lands in interviews: LCP is "did the biggest thing start loading early at high priority", CLS is "was every box reserved before its bytes arrived" — both are attribute-level decisions.

    From the lesson Resource Loading and Core Web Vitals

  18. 18. What can a markup author actually do about privacy, and what is out of scope?

    In scope and concrete: control the referrer so private URLs are not handed to third parties — referrerpolicy per element (no-referrer, strict-origin, strict-origin-when-cross-origin) and a page-wide meta name="referrer" default; use crossorigin="anonymous" so cross-origin image and script requests carry no cookies; lazy-load tracker-heavy embeds so they never fire unless the user scrolls to them; and sandbox third-party frames so they cannot reach the page. Out of scope, and honest to say so: consent management, a real privacy policy, cookie law compliance, and server-side data handling all live outside markup. The framing that lands: the markup author owns the leakage of the page’s own requests — which URL and which cookies each cross-origin fetch carries — and nothing more, but that slice is real and shipped wrong constantly.

    From the lesson Referrers, Embeds and Data Leakage

  19. 19. What does inert do that hidden and disabled do not?

    hidden removes an element from rendering entirely — nothing to see, nothing to interact with. disabled applies only to form controls and only stops interaction, while the control remains visible and announced. inert applies to ANY subtree: it stays visible but becomes non-focusable, non-clickable, excluded from find-in-page and removed from the accessibility tree — the exact contract of "the page behind a modal". The native dialog applies this automatically to everything outside it; inert is how custom overlays, off-canvas panels and hidden carousel slides get the same behavior declaratively.

    From the lesson Global Attributes, the Full Set

  20. 20. Popover or dialog — how do you choose, and what does each give you?

    Both render in the top layer. A modal dialog is for something the user must resolve: it makes the page inert, traps focus, closes on Escape and returns focus — an interruption. A popover is for something that floats alongside the page: menus, tooltips, pickers, toasts — the page stays usable, focus flows normally, and auto popovers light-dismiss on outside click or Escape while manual ones persist. The invoker rule matters: popovertarget is allowed only on buttons, because a non-interactive invoker would exclude keyboard users. Choose by "must the user deal with it first?": yes is dialog, no is popover.

    From the lesson Popovers and the menu Element

  21. 21. Why does the DOM tree show a template with no children, and what is Declarative Shadow DOM?

    The parser places a template’s children into a separate DocumentFragment (template.content), not into the tree — so the template element sits in the DOM childless while its markup waits, inert: no fetches, no script execution, no rendering, until script clones it. Declarative Shadow DOM reuses the element: a template with shadowrootmode="open" as an element’s first child makes the parser create a shadow root on that host from the template’s content — a rendered, encapsulated subtree with scoped styles (:host), filled from the host’s light-DOM children via slot elements matched by slot attributes. It renders with no JavaScript, which is what makes server-rendered, streaming web components possible; script can adopt the existing root later.

    From the lesson template, Declarative Shadow DOM and slot

  22. 22. What can markup declare about editing and dragging, and where does JavaScript take over?

    Markup declares affordances with three enumerated attributes — draggable="true|false" (a drag source, or opting a link or image out), contenteditable="true|false|plaintext-only" (an editing host, not a form control, so nothing submits), and spellcheck="true|false" — plus the keyboard-shaping pair inputmode and enterkeyhint. All three take spelled-out values; the bare-boolean form or "yes" is a conformance error and silently does nothing. JavaScript owns everything that happens next: drag/drop events and DataTransfer, drop targets, clipboard events and the Clipboard API, and reading or saving edited content. The accessibility obligation sits in markup though: drag-and-drop excludes keyboard and screen-reader users, so the button-based alternative ships with the draggable attribute, not after it.

    From the lesson Drag, Drop, Editing and Input Modes

  23. 23. How do you test a page for accessibility, and why isn’t an automated scan enough?

    Four layers. Automated DOM checks on every build — missing alt, unnamed controls, duplicate ids, dangling aria references, heading skips, empty links, contrast — fast and reliable but covering roughly a third of real failures, because a rule can see that alt exists, not that it is true. Keyboard-only on every release: reach, visible focus, sensible order, operate and escape every widget, a skip link. Screen reader on every release: navigate by headings, landmarks, links and controls; check every control has name, role and state, icon buttons are named, status changes announced. Visual: 200% and 400% zoom without horizontal scroll or overlap, contrast, reduced motion. Then a written checklist with an owner, so it happens every time.

    From the lesson Accessibility Testing: Tools, Keyboard, Screen Reader

  24. 24. What is the first rule of ARIA, and when is ARIA actually necessary?

    Use a native HTML element with the required semantics and behavior before reaching for ARIA. Native elements bring focusability, keyboard handling, states and names; ARIA only changes what is announced — role="button" on a div announces "button" but adds no keyboard activation or focus. Restating native semantics is redundant and the checker warns on it. ARIA becomes necessary for composite widgets HTML lacks — tabs, menus, trees, comboboxes — where roles name the parts (tablist/tab/tabpanel), states track selection and expansion, properties wire relationships (aria-controls, aria-labelledby), and roving tabindex defines the keyboard model; for live regions that announce changes; and for states native elements cannot express, like aria-pressed on a toggle or aria-current on the active link. Every role carries a keyboard contract from the APG that must be implemented, or the role is a lie.

    From the lesson ARIA: Roles, States and the First Rule

  25. 25. How do you keep a CMS from producing bad HTML?

    Move structure out of editors’ hands: model content as typed fields — title, images with mandatory alt, specs as label/value pairs — and let the template emit the headings, figures and lists, so accessibility and outline decisions are made once. Give editors a rich-text field constrained by a server-side sanitizer allowlist: paragraphs, h2–h4 (never h1), lists, links, emphasis, blockquote, code; no inline styles, scripts or arbitrary attributes — a quality boundary and, per HT-39, a security one. Then QA what editors still produce, in the editor: block fake bold-paragraph headings, heading skips, missing or filename alt, placeholder text; warn on empty spacer paragraphs, br chains and "click here". Imports from other systems get parsed, mapped to the model and validated rather than pasted through.

    From the lesson Content Modeling, CMS Output and Content QA

  26. 26. Why is email HTML written so differently from web HTML?

    Because mail clients are a set of inconsistent, often crippled renderers: many drop style blocks and every external stylesheet, none run scripts, most strip forms, several ignore CSS layout entirely, and a large share block remote images by default. So layout is nested tables — marked role="presentation" so screen readers do not announce them as data tables — styles are inline on each element, every URL is absolute because an email has no base, calls to action are styled links not buttons or images, every image has real alt text and dimensions so the layout survives images-off, and a hidden preheader line carries the inbox preview. Inside that scaffolding, the web’s semantics still apply: doctype, lang, charset, real headings and paragraphs, descriptive link text — and the checker still validates it, rejecting the obsolete bgcolor and cellpadding attributes old tutorials rely on.

    From the lesson Email HTML: Tables, Inline Styles and Fallbacks

  27. 27. What is foster parenting, and why does the parser do something so strange?

    In the table insertion modes the tree builder expects only table structure — caption, column groups, sections, rows, cells. When it meets anything else (text, a div, a form field outside a cell), it cannot place it inside the table without breaking the table model, so it inserts the node BEFORE the table element, as a sibling: foster parenting. Every engine does it identically because the algorithm is specified; the checker reports misplaced content and gives up on recovery. It matters wherever markup is generated or injected: a template rendered into a table without its tr, a CMS pasting a paragraph between rows, a sanitizer parsing a fragment in the wrong context — the symptom is always content appearing above the table. The deeper model: a tokenizer (with raw-text states for script/style/textarea/title) feeds tokens to a tree builder whose insertion mode decides what each token does.

    From the lesson HTML Parsing Internals: Tokenizer, Insertion Modes, Foster Parenting

  28. 28. Which security and loading controls can you set in markup, and which only in HTTP headers?

    Markup can carry: the charset (a fallback — the Content-Type header wins), a Content-Security-Policy via meta http-equiv (most directives; the header is preferred and applies earlier), the refresh pragma, referrer policy via meta name=referrer, and every link relation — preload, preconnect, stylesheet — which also exist as Link: headers and, with 103 Early Hints, arrive before the response body. Header-only: X-Frame-Options and CSP frame-ancestors for clickjacking, Cache-Control, HSTS, Cross-Origin-Opener/Embedder-Policy, Permissions-Policy. The checker enforces the boundary: http-equiv is an enumerated list, so X-Frame-Options in a meta is rejected, and a duplicate content-type meta beside meta charset is rejected. The nonce attribute is the markup half of a nonce-based CSP, matched per response to the policy.

    From the lesson HTML and HTTP Integration

  29. 29. How does a large site’s structure show up in its markup?

    In four recurring shapes. Breadcrumbs as a nav labelled Breadcrumb containing an ordered list whose order is the hierarchy, with the current page unlinked and marked aria-current — mirrored by BreadcrumbList structured data. Pagination as a nav with real links for every path, rel=prev/next on the neighbours and aria-current on the current page, even under infinite scroll. An identical landmark skeleton on every template — header, one labelled primary nav, main, footer — so assistive-tech users can predict any page, enforceable with DOM assertions. And canonical discipline at scale: facets and tracking parameters canonicalize to one indexable form, with noindex on pure filter states. Image maps — img usemap with a map of area elements each carrying alt — are the niche case where a picture is the navigation, always duplicated by a plain list of links.

    From the lesson Large-site Information Architecture

  30. 30. How do you audit a page for performance and accessibility, and what does a good finding look like?

    Four inputs, because each is blind where the others see: the validator for grammar; structural DOM checks for names, alt, dimensions and references; performance measurement (Lighthouse or field data) for LCP, CLS and INP traced back to markup causes like lazy heroes, unsized media and blocking scripts; and manual passes — keyboard, screen reader, zoom, images off, JavaScript off. Rank by user impact regardless of source: blocking (a task is impossible for some users), major (much harder), minor (friction). A finding is an observation with its evidence, the users affected, a severity and a one-line markup diff — never "improve accessibility". Then re-run all four inputs after the fixes and report the deltas; the audit is done when the after column exists, and DOM assertions turn its fixes into permanent gates.

    From the lesson Performance and Accessibility Audits

Learn it, then drill it

The HTML course teaches every one of these in context, with runnable examples. For drilling, the practice bank has 134 multiple-choice HTML questions with explanations.

Other subjects