Vanilla Is Not Dead: How I Built a Full Site in Plain HTML, CSS and JS Over One Weekend — With 15 Prompts That Actually Work
There is a special kind of pain in knowing exactly what a component should look like — and still spending four hours on a dropdown, three on a responsive grid, and another two fighting addEventListener on dynamically inserted buttons. The logic of a site is usually clear. It is the markup, the CSS cascade and the DOM that quietly eat the weekend.
A framework promises to fix this. But for a landing page, a small marketing site or a prototype, a framework means a build step, a node_modules folder, a bundler config and a stack trace you did not write. The irony: you install 200 MB of tooling to render a nav bar.
So here is the approach that saved me: keep the stack vanilla and delegate the routine to an LLM — but through structured, reusable prompts rather than casual "write me a website" requests. Below are 15 prompts I actually use, each with a usage example and working code. They follow the same contract: explicit constraints, semantic HTML, no dependencies, and a request for explanation. That contract is what separates a usable result from a plausible-looking mess.
The three rules that make vanilla prompts work
- Pin the stack. Always state: no frameworks, no build tools, ES2022, semantic HTML5, modern CSS (flex/grid, custom properties,
clamp()). Otherwise the model reaches for React out of habit. - Demand accessibility and semantics. Ask for landmarks, labels,
aria-*only where native semantics are insufficient. According to the W3C Web Content Accessibility Guidelines (WCAG 2.2, w3.org/TR/WCAG22/), semantic structure is the cheapest accessibility win you get. - Ask for the why. One line of rationale per non-obvious block catches wrong assumptions before they reach production.
| Prompt type | What it replaces | Typical time saved |
|---|---|---|
| Markup generation | Hand-typing boilerplate, landmarks | High |
| CSS layout | Trial-and-error with flex/grid | High |
| DOM logic | Event wiring, delegation, debounce | Medium |
| Debugging | Reading MDN for the fifth time | Medium |
The prompts
1. Semantic skeleton. "Generate an HTML5 document skeleton for a [site type]. Requirements: semantic landmarks (header, nav, main, footer), skip-link, <meta name=\"viewport\">, lang attribute, no inline styles, no frameworks. Comment each section's purpose." This alone kills the div-soup habit. Verify your output against the WHATWG HTML Living Standard (html.spec.whatwg.org) — it is the authoritative reference, not a random blog.
2. Responsive grid without media-query spam. "Write a CSS grid layout: 3 columns on desktop, 2 on tablet, 1 on mobile, using grid-template-columns: repeat(auto-fit, minmax(...)) where possible. Explain where a media query is still unavoidable." Modern CSS minmax() + auto-fit removes most breakpoints.
3. Fluid typography. "Create a type scale with CSS custom properties and clamp() so headings scale between 320px and 1440px viewports without media queries. Show the computed min/max values." Example: font-size: clamp(1.5rem, 1rem + 2vw, 2.5rem);
4. Accessible form with validation. "Build a contact form: labels tied to inputs, required, type=\"email\", inline error messages via aria-live=\"polite\", and a JS submit handler using the Constraint Validation API (checkValidity(), setCustomValidity()). No libraries."
5. Event delegation. "I render list items dynamically. Write a single click listener on the parent using event.target.closest(), explain why per-item listeners leak memory on re-render."
6. Debounce and throttle. "Write debounce and throttle utilities in plain JS with setTimeout/clearTimeout. Show a search-input example that fires a fetch only after 300 ms of inactivity."
7. Fetch with error handling. "Write a fetchJSON(url) helper using async/await, AbortController for timeout, and status checks. Explain why checking response.ok matters — fetch does not reject on HTTP 404." This is documented on MDN (developer.mozilla.org/en-US/docs/Web/API/Fetch_API).
8. LocalStorage wrapper. "Write a tiny storage helper that JSON-encodes values, handles quota errors, and namespaces keys. Show a theme-toggle example persisted across reloads."
9. Dark mode via custom properties. "Implement theme switching with :root custom properties and a [data-theme=\"dark\"] selector. Respect prefers-color-scheme on first load." prefers-color-scheme is a real media feature — see MDN.
10. Modal dialog done right. "Build a modal using the native <dialog> element with showModal(), focus trapping built in, Esc to close, and a backdrop click handler. Explain the difference from a div-based modal." <dialog> is part of the HTML Living Standard and widely supported.
11. Smooth scroll and anchor navigation. "Add smooth scrolling to in-page anchors with scroll-behavior: smooth, and account for a sticky header using scroll-margin-top. Respect prefers-reduced-motion."
12. Image lazy-loading and performance. "Add loading=\"lazy\" and decoding=\"async\" to below-the-fold images, width/height to prevent layout shift, and explain Core Web Vitals CLS impact." CLS is defined by web.dev (web.dev/cls/).
13. Debugging prompt. "Here is my console error and the relevant code: [paste]. Identify the cause, give the minimal fix, and explain the underlying browser behavior." Pasting the actual error text is critical — vague descriptions produce vague answers.
14. Refactor for readability. "Refactor this function: extract magic numbers into named constants, split it into single-purpose helpers, keep behavior identical. Show a diff."
15. Test checklist. "Generate a manual QA checklist for this page: keyboard navigation, screen-reader landmarks, responsive breakpoints, form edge cases (empty, invalid, very long input), and cross-browser notes." Pair with real tooling like Lighthouse for measurable checks.
What this actually changed
The pattern is boringly consistent: the prompts do not write the site for you — they remove the friction around the parts you already know how to do. You still decide the architecture, review the accessibility, and test in a real browser. The AI fills the gaps between intent and keystrokes.
Start with prompts 1–3 on your next page and see how much of the weekend comes back. If you want to go deeper into prompting discipline, browse the other guides on asibiont.com/blog — and keep vanilla alive.
Comments