html5
Document
Doctype and root:
<!doctype html>
<html lang="en">
Head basics:
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
Base URL for relative links:
<base href="https://example.com/">
Body:
</head>
<body>
...
</body>
</html>
Semantics
Layout landmarks:
<header> <nav> <main> <section> <article> <aside> <footer>
Headings:
<h1> … <h6>
Text grouping:
<p> <blockquote> <pre> <hr>
Inline text:
<strong> <em> <code> <span> <mark> <small> <time>
<abbr> <cite> <kbd> <samp> <sub> <sup> <bdi> <bdo> <data>
Lists:
<ul> <ol> <li> <dl> <dt> <dd>
Links and navigation
Link:
<a href="https://example.com">Text</a>
Open in new tab safely:
<a href="..." target="_blank" rel="noopener">
Page anchor:
<a href="#section-id"> with <section id="section-id">
Images and media
Image with alt:
<img src="image.jpg" alt="Description">
Responsive image:
<img
src="image-800.jpg"
srcset="image-400.jpg 400w, image-800.jpg 800w"
sizes="(max-width: 600px) 100vw, 600px"
alt="Description">
Figure with caption:
<figure>
<img src="..." alt="...">
<figcaption>Caption</figcaption>
</figure>
Audio/video:
<audio controls src="song.mp3"></audio>
<video controls width="640" src="movie.mp4"></video>
Picture art direction:
<picture>
<source media="(min-width: 800px)" srcset="wide.jpg">
<img src="fallback.jpg" alt="Description">
</picture>
Media text tracks:
<video controls src="movie.mp4">
<track kind="subtitles" srclang="en" src="subs.vtt" default>
</video>
Tables
Basic table:
<table>
<caption>Caption</caption>
<thead>
<tr><th scope="col">A</th><th scope="col">B</th></tr>
</thead>
<tbody>
<tr><td>1</td><td>2</td></tr>
</tbody>
</table>
Table columns:
<colgroup>
<col span="2">
<col class="highlight">
</colgroup>
Forms
Form structure:
<form action="/submit" method="post">
<label for="email">Email</label>
<input id="email" name="email" type="email" required>
<button type="submit">Send</button>
</form>
Common inputs:
text email password number date time datetime-local month week
checkbox radio range color file tel url search hidden
Input helpers:
placeholder required min max step minlength maxlength
pattern autocomplete autofocus disabled readonly
inputmode enterkeyhint autocapitalize spellcheck
Textarea and select:
<textarea name="message" rows="4"></textarea>
<select name="size">
<option value="s">Small</option>
</select>
Grouped controls:
<fieldset>
<legend>Shipping</legend>
...
</fieldset>
Form validation:
required pattern type="email" type="url"
Forms (advanced)
Datalist:
<input list="cities" name="city">
<datalist id="cities">
<option value="Paris">
</datalist>
Progress and meter:
<progress value="30" max="100"></progress>
<meter value="0.6" min="0" max="1"></meter>
Output:
<output name="total">42</output>
Button overrides:
<button formaction="/save" formmethod="post">Save</button>
<button formnovalidate>Skip validation</button>
Multiple files:
<input type="file" multiple>
Capture from device:
<input type="file" accept="image/*" capture="environment">
Interactive
Details/summary:
<details>
<summary>More</summary>
<p>Hidden content</p>
</details>
Dialog:
<dialog open>Dialog content</dialog>
Editable content:
<div contenteditable="true"></div>
Metadata and SEO
Description and icons:
<meta name="description" content="...">
<link rel="icon" href="/favicon.ico">
Canonical and robots:
<link rel="canonical" href="https://example.com/page">
<meta name="robots" content="index,follow">
Social previews:
<meta property="og:title" content="...">
<meta property="og:image" content="...">
Scripts and modules
Defer/async:
<script src="app.js" defer></script>
<script src="analytics.js" async></script>
Modules:
<script type="module" src="app.mjs"></script>
Import maps:
<script type="importmap">
{
"imports": {
"lit": "https://cdn.example.com/lit.js"
}
}
</script>
Preload module:
<link rel="modulepreload" href="/app.mjs">
Noscript:
<noscript>Enable JavaScript</noscript>
Templates
Template element:
<template id="card-template">
<article class="card">...</article>
</template>
Slots (web components):
<my-card>
<span slot="title">Title</span>
</my-card>
Accessibility
Landmarks and labels:
<main> <nav> <header> <footer> <label for="id">
Alt text:
<img alt="Meaningful description">
ARIA basics:
role="dialog" aria-label="Close" aria-expanded="false"
Embeds
Iframes:
<iframe src="..." title="Description"></iframe>
Inline SVG:
<svg viewBox="0 0 24 24" aria-hidden="true">
<path d="..."></path>
</svg>
Storage and offline
Local/session storage:
<script>
localStorage.setItem("theme", "dark");
const theme = localStorage.getItem("theme");
sessionStorage.setItem("draft", "...");
</script>
Offline hint:
<meta name="theme-color" content="#111111">
Storage limits (browser-dependent):
navigator.storage.estimate().then(({ quota, usage }) => {})
IndexedDB (open DB):
<script>
const request = indexedDB.open("app-db", 1);
request.onupgradeneeded = () => {
const db = request.result;
db.createObjectStore("items", { keyPath: "id" });
};
</script>
Cache API (in SW):
<script>
// sw.js
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then((cached) => cached || fetch(event.request))
);
});
</script>
Service workers
Register service worker:
<script>
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js");
}
</script>
Basic cache in sw:
<script>
// sw.js
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open("v1").then((cache) => cache.addAll(["/"]))
);
});
</script>
PWA manifest
Manifest link:
<link rel="manifest" href="/manifest.json">
Basic manifest:
<script>
// manifest.json
{
"name": "App",
"short_name": "App",
"start_url": "/",
"display": "standalone",
"icons": [{ "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }]
}
</script>
History and navigation
History API:
<script>
history.pushState({ page: 2 }, "", "?page=2");
window.addEventListener("popstate", (e) => {});
</script>
Location helpers:
location.href location.search location.hash
Fetch and streams
Fetch with abort:
<script>
const controller = new AbortController();
fetch("/api", { signal: controller.signal });
controller.abort();
</script>
Readable stream:
<script>
const stream = new ReadableStream({
start(controller) { controller.enqueue(new TextEncoder().encode("hi")); }
});
</script>
Drag and drop
Draggable element:
<div draggable="true"></div>
Drop target:
<div ondragover="event.preventDefault()" ondrop="onDrop(event)"></div>
Canvas
Canvas element:
<canvas id="chart" width="300" height="150"></canvas>
Basic drawing:
<script>
const ctx = document.getElementById("chart").getContext("2d");
ctx.fillStyle = "#0ea5e9";
ctx.fillRect(10, 10, 100, 50);
</script>
WebSocket
Connect and send:
<script>
const ws = new WebSocket("wss://example.com/socket");
ws.addEventListener("open", () => ws.send("hello"));
ws.addEventListener("message", (e) => {});
</script>
Workers
Web worker:
<script>
const worker = new Worker("worker.js");
worker.postMessage({ task: "work" });
</script>
Shared worker:
<script>
const worker = new SharedWorker("shared.js");
worker.port.start();
</script>
Geolocation
Get current position:
<script>
navigator.geolocation.getCurrentPosition(
(pos) => {},
(err) => {},
{ enableHighAccuracy: true }
);
</script>
Permissions
Query permission state:
<script>
navigator.permissions.query({ name: "geolocation" })
.then((status) => {
console.log(status.state);
});
</script>
Prompt on use:
navigator.geolocation.getCurrentPosition(...)
navigator.mediaDevices.getUserMedia(...)
Events
Pointer and touch:
pointerdown pointermove touchstart
Keyboard:
keydown keyup input
Passive listener:
<script>
window.addEventListener("scroll", () => {}, { passive: true });
</script>
WebRTC
Get media stream:
<script>
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then((stream) => {
const video = document.querySelector("video");
video.srcObject = stream;
});
</script>
Peer connection (minimal):
<script>
const pc = new RTCPeerConnection();
pc.onicecandidate = (e) => {};
</script>
Web Audio
Audio context and oscillator:
<script>
const ctx = new AudioContext();
const osc = ctx.createOscillator();
osc.connect(ctx.destination);
osc.start();
osc.stop(ctx.currentTime + 0.5);
</script>
Clipboard and share
Clipboard read/write:
<script>
navigator.clipboard.writeText("hello");
navigator.clipboard.readText().then((text) => {});
</script>
Web Share API:
<script>
navigator.share({ title: "Title", url: "https://example.com" });
</script>
Notifications and badges
Notifications:
<script>
Notification.requestPermission().then((perm) => {
if (perm === "granted") new Notification("Hello");
});
</script>
App badge:
navigator.setAppBadge(3)
navigator.clearAppBadge()
File System Access
Pick file and read:
<script>
const [handle] = await window.showOpenFilePicker();
const file = await handle.getFile();
</script>
Security and performance
CSP meta:
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">
SRI for scripts:
<script src="app.js" integrity="sha384-..." crossorigin="anonymous"></script>
Preconnect and DNS prefetch:
<link rel="preconnect" href="https://cdn.example.com">
<link rel="dns-prefetch" href="//cdn.example.com">
Referrer policy:
<meta name="referrer" content="no-referrer">
Fetch priority hints:
<img src="hero.jpg" fetchpriority="high">