HTML5

Semantic elements, forms, tables, media, accessibility attributes and browser APIs — the parts of HTML5 you reach for most.

Every HTML5 tag at a glance

Every entry, one line each. Highlighted ones have a detailed example below — click to jump there.

html
The root element of the document
head
Container for document metadata
body
Container for the visible page content
title
The document's title, shown in the browser tab
meta
Metadata that cannot be expressed by other elements
link
Links the document to an external resource
base
The base URL for all relative URLs in the document
style
Embeds CSS directly in the document
script
Embeds or references executable JavaScript
noscript
Fallback content when scripting is disabled
div
A generic block-level container with no semantic meaning
span
A generic inline container with no semantic meaning
p
A paragraph of text
a
A hyperlink to another page, file, or location
ul
An unordered (bulleted) list
ol
An ordered (numbered) list
li
A list item, inside <ul> or <ol>
dl / dt / dd
A description list, its terms, and their descriptions
blockquote
An extended quotation from another source
q
A short, inline quotation
cite
The title of a creative work being referenced
address
Contact information for the nearest article or body
hr
A thematic break between paragraph-level content
br
A single line break
pre
Preformatted text — whitespace is preserved
article
Self-contained, independently distributable content
aside
Content tangentially related to the surrounding content
section
A generic standalone section of a document
nav
A section with navigation links
header
Introductory content, typically a group of navigational aids
footer
A footer for its nearest sectioning content
main
The dominant content of the document body
figure / figcaption
Self-contained content and its caption
details / summary
A disclosure widget and its always-visible label
dialog
A dialog box or other interactive component
time
A specific period in time
mark
Text marked or highlighted for reference purposes
template
A mechanism for holding HTML that isn't rendered immediately
data
Links content with a machine-readable value
bdi
Isolates text that might be formatted in a different direction
wbr
A word break opportunity
strong / em
Strong importance, and stress emphasis
b / i / u
Stylistically offset text, alternate voice, and underline
small
Side comments and small print
del / ins
Deleted and inserted text (tracked changes)
sub / sup
Subscript and superscript text
code / kbd / samp / var
Code, keyboard input, sample output, and variables
abbr
An abbreviation or acronym, with its full form in title
form
A section for collecting and submitting user input
input
A form control — its type attribute picks the widget
textarea
A multi-line plain-text input control
button
A clickable button
select / option
A dropdown list and its options
optgroup
Groups related <option>s under a label
label
Caption for a form control, tied to it via 'for'
fieldset / legend
Groups related form controls, with a caption
datalist
A set of predefined options for an input
output
The result of a calculation or user action
meter
A scalar value within a known range, or a fractional value
progress
The completion progress of a task
img
Embeds an image
audio
Embeds a sound or audio stream
video
Embeds a video
source
Media resources for <picture>, <audio> or <video>
track
Text tracks (captions, subtitles) for media elements
picture
A container for multiple image sources
iframe
Embeds another HTML page within the current one
embed
Embeds external content at the point in the document
object
Embeds external resources via a plugin or the browser
canvas
A bitmap area for drawing via JavaScript
svg
Embeds scalable vector graphics
map / area
A client-side image map and its clickable regions
table
Represents tabular data
thead / tbody / tfoot
Groups the header, body, and footer rows of a table
tr
A row of table cells
td / th
A data cell, and a header cell
caption
A table's title
colgroup / col
Groups and styles one or more table columns

Worked examples with live previews, for the parts worth seeing in action.

Document & Metadata

Boilerplate & Essential Meta Tags

<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="description" content="Page summary for search engines" />
    <title>Page Title</title>
  </head>
  <body></body>
</html>

lang drives screen-reader pronunciation and spell-check. The viewport meta tag is required for responsive layouts on mobile.

The minimum head every HTML5 document should start with.

  • doctype
  • meta
  • viewport
  • charset
  • head

Favicon & Social Preview Tags

<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />

<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Page summary" />
<meta property="og:type" content="website" />
<meta property="og:url" content="https://example.com/page" />
<meta property="og:image" content="https://example.com/og-image.png" />
<meta name="twitter:card" content="summary_large_image" />

og:image must be an absolute URL — Facebook, Slack and LinkedIn won’t resolve a relative path.

Icons and Open Graph/Twitter tags for link previews.

  • favicon
  • open graph
  • og
  • twitter card
  • social

Semantic Elements

Landmark & Sectioning Elements

<header>Site or section header</header>
<nav>Primary navigation</nav>
<main>
  <article>Self-contained, independently distributable content</article>
  <section>Thematic grouping, usually with a heading</section>
</main>
<aside>Tangentially related content</aside>
<footer>Site or section footer</footer>

No role attribute needed — but the mapping has conditions: <header>/<footer> only become banner/contentinfo landmarks when they’re not nested inside <article>, <section>, <aside> or <nav>, and <section> only becomes a region landmark once it has an accessible name (a heading, or aria-label). Use <section> only when the content has its own heading; otherwise prefer <div>.

Structural elements that replace generic <div> soup.

  • header
  • nav
  • main
  • article
  • section
  • aside
  • footer
  • landmarks

Text-Level Semantics

<mark>Highlighted</mark> search term.
<time datetime="2026-08-26">August 26, 2026</time>
<abbr title="Cascading Style Sheets">CSS</abbr>

<details>
  <summary>Click to expand</summary>
  Revealed content, no JavaScript required.
</details>

Press <kbd>Ctrl</kbd> + <kbd>K</kbd> to search.
Preview

Highlighted search term.
CSS

Click to expand Revealed content, no JavaScript required.

Press Ctrl + K to search.

Inline elements that carry real meaning, not just styling.

  • mark
  • time
  • abbr
  • details
  • summary
  • code
  • kbd

Forms

Modern Input Types

<input type="email" name="email" />
<input type="url" name="site" />
<input type="tel" name="phone" />
<input type="date" name="due" />
<input type="range" min="0" max="100" step="10" />
<input type="color" name="accent" />
<input type="search" name="q" />

email/url/tel/number get built-in validation and the right on-screen keyboard on mobile. date swaps in a picker instead of a keyboard; range and color can never be invalid, since any value in their range is valid.

Preview

Built-in inputs for email, dates, color and more — with native UI and mobile keyboards.

  • input
  • email
  • date
  • range
  • color
  • forms

Native Validation Attributes

<input type="text" required minlength="3" maxlength="24" />
<input type="text" pattern="[A-Za-z]+" title="Letters only" />
<input type="number" min="1" max="10" step="1" />
<input type="password" required autocomplete="new-password" />

pattern is implicitly anchored — no need to wrap it in ^…$. Prefer :user-invalid/:user-valid over plain :invalid/:valid for styling: the plain versions paint an empty required field red before the user has typed anything. Combine with the Constraint Validation API (el.checkValidity()) for custom error UI.

Constrain and validate form input without JavaScript.

  • required
  • pattern
  • minlength
  • validation
  • forms

Tables

Table Structure

<table>
  <caption>Quarterly revenue by region</caption>
  <thead>
    <tr>
      <th scope="col">Region</th>
      <th scope="col">Q1</th>
      <th scope="col">Q2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">EMEA</th>
      <td>$42k</td>
      <td>$48k</td>
    </tr>
  </tbody>
</table>

The elements that group and describe tabular data.

caption
The table's title — must be the first child of <table>
thead / tbody / tfoot
Groups header, body and footer rows so they can be styled and scrolled separately
scope
On a <th>, tells assistive tech whether it heads a "col" or a "row"
  • table
  • thead
  • tbody
  • tfoot
  • caption
  • scope

Spanning Cells & Sticky Headers

<table>
  <tr>
    <th id="name">Name</th>
    <th id="q1">Q1</th>
    <th id="q2">Q2</th>
  </tr>
  <tr>
    <td headers="name">EMEA</td>
    <td headers="q1">$42k</td>
    <td headers="q2">$48k</td>
  </tr>
  <tr>
    <td colspan="3">Totals below</td>
  </tr>
</table>
thead th {
  position: sticky;
  top: 0;
  background: var(--bg-raised);
}

Merging cells, and keeping the header visible on a long, scrolling table.

colspan / rowspan
Merges a cell across multiple columns or rows
headers
On a <td>, explicitly associates it with one or more <th> ids for complex tables
  • colspan
  • rowspan
  • headers
  • sticky

Media & Embeds

Responsive Images with <picture>

<!-- above the fold: load eagerly and with priority, not lazily -->
<picture>
  <source srcset="hero-wide.avif" media="(min-width: 800px)" type="image/avif" />
  <source srcset="hero.avif" type="image/avif" />
  <img src="hero.jpg" alt="Description of the image" width="1600" height="900" fetchpriority="high" decoding="async" />
</picture>

<!-- further down the page: lazy-load is the right call -->
<img
  src="photo-800.jpg"
  srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
  sizes="(min-width: 900px) 800px, 100vw"
  width="800"
  height="533"
  loading="lazy"
  alt="Description"
/>

width/height (or aspect-ratio in CSS) reserve space before the image loads, preventing layout shift. loading="lazy" on a hero image is a common LCP mistake — reserve it for images below the fold.

Serve different image files by viewport size or format support.

srcset
Candidate image files, each tagged with a width or pixel density
sizes
The rendered width of the image at each breakpoint
loading
"lazy" defers off-screen images — never use it on an above-the-fold hero
fetchpriority
"high" tells the browser to fetch a critical image (like a hero) sooner
  • picture
  • srcset
  • sizes
  • source
  • images

<video> & <audio>

<video controls muted autoplay playsinline poster="poster.jpg" width="640">
  <source src="clip.webm" type="video/webm" />
  <source src="clip.mp4" type="video/mp4" />
  <track kind="captions" src="captions.vtt" srclang="en" label="English" default />
  Your browser doesn't support video playback.
</video>

<audio controls src="track.mp3"></audio>

Native media playback with captions and multiple source formats.

controls
Shows the browser-native play/pause/volume UI
muted
Starts silent — required for autoplay in most browsers
playsinline
Plays inline on mobile instead of forcing fullscreen
poster
Image shown before playback starts
track default
Pre-selects that track — it does not force captions on for the viewer
  • video
  • audio
  • controls
  • track
  • captions

Global Attributes

Attributes Available on Every Element

<div id="unique" class="a b c" data-state="open" data-index="2"></div>
<div tabindex="0">Focusable via keyboard</div>
<div contenteditable="true">Editable in place</div>
<div hidden>Not rendered, not in the accessibility tree</div>
<div draggable="true">Drag me</div>

Read data-* attributes in JS via el.dataset.state / el.dataset.index.

id, data-*, tabindex and friends — usable on any HTML element.

  • id
  • class
  • data attribute
  • tabindex
  • contenteditable
  • hidden

ARIA & Accessibility Attributes

<button aria-label="Close dialog">×</button>
<div role="status">Saved</div>
<svg aria-hidden="true"><!-- decorative --></svg>
<nav aria-label="Breadcrumb"></nav>
<button aria-expanded="false" aria-controls="menu">Menu</button>

Rule of thumb: prefer a native element (<button>, <nav>) over ARIA-on-a-<div> whenever one exists. role="status" already implies aria-live="polite" — adding it explicitly is redundant, not wrong, just unnecessary.

Fill accessibility gaps when semantic HTML alone is not enough.

  • aria
  • role
  • aria-label
  • aria-hidden
  • accessibility

Browser APIs

Web Storage

// Survives across tabs and browser restarts
localStorage.setItem('theme', 'dark');
localStorage.getItem('theme'); // "dark"
localStorage.removeItem('theme');

// Cleared when the tab closes
sessionStorage.setItem('draft', JSON.stringify({ title: '' }));

// React to changes from other tabs
window.addEventListener('storage', (e) => {
  console.log(e.key, e.oldValue, e.newValue);
});

Persist data client-side without a server round trip.

  • localStorage
  • sessionStorage
  • storage
  • api

Geolocation & Canvas

navigator.geolocation.getCurrentPosition(
  (pos) => console.log(pos.coords.latitude, pos.coords.longitude),
  (err) => console.error(err.message),
  { enableHighAccuracy: true, timeout: 5000 }
);
<canvas id="scene" width="400" height="300"></canvas>
<script>
  const ctx = document.getElementById('scene').getContext('2d');
  ctx.fillStyle = '#a78bfa';
  ctx.fillRect(20, 20, 100, 60);
</script>

Geolocation only works in a secure context (https:// or localhost) — it fails silently everywhere else.

Two of the most commonly used browser APIs, quick reference.

  • geolocation
  • canvas
  • api
  • getContext
webcheet