Available for day contractsFrom 21st September I have availability for day and half day contracts. Please contact for more information.

Contact →
mikepreston.org

HTML5

A comprehensive guide to HTML5 semantic elements, forms, media, accessibility, and modern document structure patterns.

HTML5 Cheatsheet

A comprehensive guide to HTML5 semantic elements, forms, media, accessibility, and modern document structure patterns.


Overview

HTML5 is the fifth major revision of the HyperText Markup Language, introducing semantic elements, native multimedia support, improved forms, and enhanced accessibility features for building modern, well-structured web documents.

HTML5 Core FeaturesHTML5 DocumentSemantic StructureForms & ValidationMedia ElementsGraphicsAccessibilityMetadata & SEOheader/footernav/mainarticle/sectionaside/figureInput TypesValidationAttributesaudiovideopictureCanvasSVGARIARolesData AttributesHTML5 Core FeaturesHTML5 DocumentSemantic StructureForms & ValidationMedia ElementsGraphicsAccessibilityMetadata & SEOheader/footernav/mainarticle/sectionaside/figureInput TypesValidationAttributesaudiovideopictureCanvasSVGARIARolesData Attributes

Semantic Elements

Key Concepts

Semantic HTML5 elements provide meaning to the structure of web content, improving accessibility, SEO, and code maintainability. They replace generic <div> elements with descriptive tags that indicate the purpose of content.

Semantic Document LayoutbodyheadernavmainfooterarticlesectionasidefigurefigcaptionSemantic Document Layoutbodyheadernavmainfooterarticlesectionasidefigurefigcaption

Common Patterns

Element Purpose Usage
<header> Introductory content or navigation Page header, article header
<nav> Navigation links Main menu, breadcrumbs, pagination
<main> Main content (unique per page) Primary content area
<article> Self-contained content Blog post, news article, comment
<section> Thematic grouping Chapters, tabbed content
<aside> Tangentially related content Sidebars, pull quotes, advertisements
<footer> Footer information Copyright, contact info, related links
<figure> Self-contained media Images, diagrams, code listings
<figcaption> Caption for figure Image descriptions

Examples

Basic Page Structure

<!DOCTYPE html>
<html lang="en-GB">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Page Title</title>
</head>
<body>
    <header>
        <h1>Site Title</h1>
        <nav>
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/about">About</a></li>
                <li><a href="/contact">Contact</a></li>
            </ul>
        </nav>
    </header>

    <main>
        <article>
            <header>
                <h2>Article Title</h2>
                <p>Published on <time datetime="2025-01-15">15 January 2025</time></p>
            </header>

            <section>
                <h3>Introduction</h3>
                <p>Article content goes here...</p>
            </section>

            <section>
                <h3>Main Points</h3>
                <p>More content...</p>

                <figure>
                    <img src="diagram.png" alt="Explanatory diagram">
                    <figcaption>Figure 1: System architecture overview</figcaption>
                </figure>
            </section>

            <footer>
                <p>Author: Jane Smith</p>
            </footer>
        </article>

        <aside>
            <h3>Related Articles</h3>
            <ul>
                <li><a href="/article-2">Related Topic</a></li>
            </ul>
        </aside>
    </main>

    <footer>
        <p>&copy; 2025 Organisation Name. All rights reserved.</p>
        <address>
            Contact: <a href="mailto:info@example.com">info@example.com</a>
        </address>
    </footer>
</body>
</html>

Article with Multiple Sections

<article>
    <header>
        <h1>Understanding HTML5 Semantics</h1>
        <p>A comprehensive guide to modern markup</p>
    </header>

    <section id="introduction">
        <h2>Introduction</h2>
        <p>HTML5 semantic elements improve document structure...</p>
    </section>

    <section id="benefits">
        <h2>Benefits</h2>
        <ul>
            <li>Better accessibility</li>
            <li>Improved SEO</li>
            <li>Clearer code organisation</li>
        </ul>
    </section>

    <section id="conclusion">
        <h2>Conclusion</h2>
        <p>Adopting semantic HTML improves web standards...</p>
    </section>
</article>

Forms

Key Concepts

HTML5 forms introduce new input types, built-in validation, and attributes that reduce reliance on JavaScript for common form behaviours. Native validation provides better user experience and accessibility.

Input Types

Type Description Example
text Single-line text <input type="text">
email Email address with validation <input type="email">
password Masked text input <input type="password">
number Numeric input with spinners <input type="number" min="0" max="100">
range Slider control <input type="range" min="0" max="100">
date Date picker <input type="date">
time Time picker <input type="time">
datetime-local Date and time picker <input type="datetime-local">
month Month and year picker <input type="month">
week Week picker <input type="week">
tel Telephone number <input type="tel">
url URL with validation <input type="url">
search Search field <input type="search">
color Colour picker <input type="color">
file File upload <input type="file" accept=".pdf,.doc">
hidden Hidden data <input type="hidden" name="token">
checkbox Checkbox <input type="checkbox">
radio Radio button <input type="radio">

Validation Attributes

Attribute Description Example
required Field must be filled <input required>
pattern Regex pattern match <input pattern="[A-Za-z]{3}">
min / max Minimum/maximum value <input type="number" min="1" max="10">
minlength / maxlength Character limits <input minlength="8" maxlength="20">
step Increment value <input type="number" step="0.01">
multiple Allow multiple values <input type="email" multiple>

Form Attributes

Attribute Description Example
placeholder Hint text <input placeholder="Enter name">
autofocus Focus on page load <input autofocus>
autocomplete Browser autocomplete <input autocomplete="email">
readonly Read-only field <input readonly>
disabled Disabled field <input disabled>
form Associate with form <input form="myform">
list Datalist reference <input list="options">
novalidate Skip validation <form novalidate>
formnovalidate Skip validation on submit <button formnovalidate>

Examples

Complete Registration Form

<form action="/register" method="POST" id="registration">
    <fieldset>
        <legend>Personal Information</legend>

        <div>
            <label for="fullname">Full Name:</label>
            <input type="text" id="fullname" name="fullname"
                   required minlength="2" maxlength="100"
                   placeholder="Enter your full name"
                   autocomplete="name">
        </div>

        <div>
            <label for="email">Email:</label>
            <input type="email" id="email" name="email"
                   required placeholder="you@example.com"
                   autocomplete="email">
        </div>

        <div>
            <label for="phone">Phone:</label>
            <input type="tel" id="phone" name="phone"
                   pattern="[0-9]{11}"
                   placeholder="07123456789"
                   autocomplete="tel">
        </div>

        <div>
            <label for="dob">Date of Birth:</label>
            <input type="date" id="dob" name="dob"
                   min="1900-01-01" max="2010-12-31">
        </div>
    </fieldset>

    <fieldset>
        <legend>Account Details</legend>

        <div>
            <label for="username">Username:</label>
            <input type="text" id="username" name="username"
                   required pattern="[a-zA-Z0-9_]{3,20}"
                   title="3-20 characters, letters, numbers, underscores only"
                   autocomplete="username">
        </div>

        <div>
            <label for="password">Password:</label>
            <input type="password" id="password" name="password"
                   required minlength="8"
                   pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}"
                   title="Must contain at least one number, one uppercase and lowercase letter, and at least 8 characters"
                   autocomplete="new-password">
        </div>

        <div>
            <label for="website">Website:</label>
            <input type="url" id="website" name="website"
                   placeholder="https://example.com">
        </div>
    </fieldset>

    <fieldset>
        <legend>Preferences</legend>

        <div>
            <label for="country">Country:</label>
            <input type="text" id="country" name="country" list="countries">
            <datalist id="countries">
                <option value="United Kingdom">
                <option value="United States">
                <option value="Australia">
                <option value="Canada">
            </datalist>
        </div>

        <div>
            <label for="experience">Experience Level:</label>
            <input type="range" id="experience" name="experience"
                   min="1" max="10" value="5">
            <output for="experience">5</output>
        </div>

        <div>
            <label for="colour">Favourite Colour:</label>
            <input type="color" id="colour" name="colour" value="#3498db">
        </div>

        <div>
            <label>
                <input type="checkbox" name="newsletter" value="yes">
                Subscribe to newsletter
            </label>
        </div>
    </fieldset>

    <div>
        <button type="submit">Register</button>
        <button type="reset">Clear Form</button>
    </div>
</form>

Search Form with Datalist

<form action="/search" method="GET">
    <label for="search">Search:</label>
    <input type="search" id="search" name="q"
           list="suggestions" autofocus
           placeholder="Search...">
    <datalist id="suggestions">
        <option value="HTML5">
        <option value="CSS3">
        <option value="JavaScript">
        <option value="Web Components">
    </datalist>
    <button type="submit">Search</button>
</form>

Form with Output Element

<form oninput="result.value=parseInt(a.value)+parseInt(b.value)">
    <input type="number" id="a" name="a" value="0"> +
    <input type="number" id="b" name="b" value="0"> =
    <output name="result" for="a b">0</output>
</form>

Media Elements

Key Concepts

HTML5 provides native support for audio and video playback without plugins. The <picture> element enables responsive images, while <source> elements specify multiple media resources for browser selection.

Audio Element

<!-- Basic audio -->
<audio src="audio.mp3" controls></audio>

<!-- Multiple sources with fallback -->
<audio controls preload="metadata">
    <source src="audio.ogg" type="audio/ogg">
    <source src="audio.mp3" type="audio/mpeg">
    <source src="audio.wav" type="audio/wav">
    <p>Your browser does not support audio playback.</p>
</audio>

<!-- Audio with attributes -->
<audio controls autoplay loop muted>
    <source src="background.mp3" type="audio/mpeg">
</audio>

Video Element

<!-- Basic video -->
<video src="video.mp4" controls width="640" height="360"></video>

<!-- Multiple sources with subtitles -->
<video controls width="800" height="450" poster="thumbnail.jpg" preload="metadata">
    <source src="video.webm" type="video/webm">
    <source src="video.mp4" type="video/mp4">
    <source src="video.ogv" type="video/ogg">

    <!-- Subtitles and captions -->
    <track kind="subtitles" src="subs-en.vtt" srclang="en" label="English" default>
    <track kind="subtitles" src="subs-fr.vtt" srclang="fr" label="Français">
    <track kind="captions" src="captions.vtt" srclang="en" label="English Captions">

    <p>Your browser does not support video playback.</p>
</video>

Picture Element (Responsive Images)

<!-- Art direction: different crops for different viewports -->
<picture>
    <source media="(min-width: 1200px)" srcset="hero-large.jpg">
    <source media="(min-width: 768px)" srcset="hero-medium.jpg">
    <img src="hero-small.jpg" alt="Hero image description">
</picture>

<!-- Format selection: modern formats with fallback -->
<picture>
    <source srcset="image.avif" type="image/avif">
    <source srcset="image.webp" type="image/webp">
    <img src="image.jpg" alt="Image description">
</picture>

<!-- Combined: responsive with format selection -->
<picture>
    <source media="(min-width: 1200px)"
            srcset="large.avif" type="image/avif">
    <source media="(min-width: 1200px)"
            srcset="large.webp" type="image/webp">
    <source media="(min-width: 1200px)"
            srcset="large.jpg" type="image/jpeg">
    <source media="(min-width: 768px)"
            srcset="medium.webp" type="image/webp">
    <source srcset="small.webp" type="image/webp">
    <img src="small.jpg" alt="Responsive image"
         loading="lazy" decoding="async">
</picture>

Media Attributes Reference

Attribute Elements Description
controls audio, video Show playback controls
autoplay audio, video Start playing automatically
loop audio, video Loop playback
muted audio, video Mute audio
preload audio, video Preload hint: none, metadata, auto
poster video Preview image
width / height video Dimensions
playsinline video Play inline on mobile
crossorigin audio, video CORS settings

Track Element Kinds

Kind Description
subtitles Translations of dialogue
captions Transcription including sound effects
descriptions Text descriptions of video
chapters Chapter titles for navigation
metadata Machine-readable data

Canvas and SVG Basics

Key Concepts

Canvas provides a bitmap drawing surface for dynamic graphics via JavaScript. SVG (Scalable Vector Graphics) is an XML-based format for resolution-independent vector graphics that can be styled with CSS and manipulated with JavaScript.

Canvas Basics

<!-- Canvas element -->
<canvas id="myCanvas" width="400" height="300">
    Your browser does not support canvas.
</canvas>

<script>
const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

// Rectangle
ctx.fillStyle = '#3498db';
ctx.fillRect(10, 10, 100, 80);

// Stroke rectangle
ctx.strokeStyle = '#e74c3c';
ctx.lineWidth = 3;
ctx.strokeRect(130, 10, 100, 80);

// Path (triangle)
ctx.beginPath();
ctx.moveTo(250, 90);
ctx.lineTo(290, 10);
ctx.lineTo(330, 90);
ctx.closePath();
ctx.fillStyle = '#2ecc71';
ctx.fill();

// Circle
ctx.beginPath();
ctx.arc(60, 150, 40, 0, Math.PI * 2);
ctx.fillStyle = '#9b59b6';
ctx.fill();

// Text
ctx.font = '20px Arial';
ctx.fillStyle = '#333';
ctx.fillText('Hello Canvas', 120, 160);

// Line
ctx.beginPath();
ctx.moveTo(10, 220);
ctx.lineTo(380, 220);
ctx.strokeStyle = '#f39c12';
ctx.lineWidth = 2;
ctx.stroke();

// Gradient
const gradient = ctx.createLinearGradient(10, 250, 200, 250);
gradient.addColorStop(0, '#3498db');
gradient.addColorStop(1, '#e74c3c');
ctx.fillStyle = gradient;
ctx.fillRect(10, 240, 200, 40);
</script>

SVG Basics

<!-- Inline SVG -->
<svg width="400" height="300" xmlns="http://www.w3.org/2000/svg">
    <!-- Rectangle -->
    <rect x="10" y="10" width="100" height="80" fill="#3498db"/>

    <!-- Rectangle with stroke -->
    <rect x="130" y="10" width="100" height="80"
          fill="none" stroke="#e74c3c" stroke-width="3"/>

    <!-- Circle -->
    <circle cx="60" cy="150" r="40" fill="#9b59b6"/>

    <!-- Ellipse -->
    <ellipse cx="180" cy="150" rx="50" ry="30" fill="#f39c12"/>

    <!-- Line -->
    <line x1="10" y1="220" x2="380" y2="220"
          stroke="#2ecc71" stroke-width="2"/>

    <!-- Polyline -->
    <polyline points="10,280 50,250 90,280 130,250 170,280"
              fill="none" stroke="#3498db" stroke-width="2"/>

    <!-- Polygon (triangle) -->
    <polygon points="250,90 290,10 330,90" fill="#2ecc71"/>

    <!-- Path -->
    <path d="M 200 250 Q 250 200 300 250 T 400 250"
          fill="none" stroke="#e74c3c" stroke-width="2"/>

    <!-- Text -->
    <text x="250" y="160" font-family="Arial" font-size="20" fill="#333">
        Hello SVG
    </text>

    <!-- Group with transform -->
    <g transform="translate(300, 50) rotate(45)">
        <rect x="0" y="0" width="30" height="30" fill="#9b59b6"/>
    </g>
</svg>

SVG with CSS Styling

<style>
    .icon {
        width: 24px;
        height: 24px;
        fill: currentColor;
    }
    .icon:hover {
        fill: #3498db;
    }
    .animated-circle {
        animation: pulse 2s infinite;
    }
    @keyframes pulse {
        0%, 100% { r: 20; }
        50% { r: 30; }
    }
</style>

<svg class="icon" viewBox="0 0 24 24">
    <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
</svg>

<svg width="100" height="100">
    <circle class="animated-circle" cx="50" cy="50" r="20" fill="#3498db"/>
</svg>

Canvas vs SVG Comparison

Feature Canvas SVG
Type Bitmap (raster) Vector
Scaling Pixelates Resolution independent
DOM Access No Yes (each element)
Event Handling Manual (coordinates) Native (per element)
Performance Better for many objects Better for few, complex objects
Best For Games, image editing Icons, charts, diagrams
Accessibility Requires extra effort Built-in text support

Data Attributes

Key Concepts

Custom data attributes (data-*) allow storing extra information on HTML elements without affecting presentation or behaviour. They are accessible via JavaScript and CSS, providing a clean way to attach metadata to elements.

Syntax and Usage

<!-- Basic data attributes -->
<div id="user"
     data-user-id="12345"
     data-role="admin"
     data-active="true"
     data-last-login="2025-01-15T10:30:00Z">
    User Profile
</div>

<!-- Data attributes on various elements -->
<button data-action="delete" data-confirm="Are you sure?">Delete</button>

<article data-category="technology"
         data-author="Jane Smith"
         data-publish-date="2025-01-15"
         data-read-time="5">
    Article content...
</article>

<li data-product-id="SKU123"
    data-price="29.99"
    data-currency="GBP"
    data-in-stock="true">
    Product Item
</li>

JavaScript Access

<div id="config"
     data-api-url="https://api.example.com"
     data-max-retries="3"
     data-enable-cache="true">
</div>

<script>
const element = document.getElementById('config');

// Using dataset property (camelCase)
console.log(element.dataset.apiUrl);      // "https://api.example.com"
console.log(element.dataset.maxRetries);  // "3"
console.log(element.dataset.enableCache); // "true"

// Setting data attributes
element.dataset.timeout = "5000";
element.dataset.newFeature = "enabled";

// Using getAttribute/setAttribute (kebab-case)
console.log(element.getAttribute('data-api-url'));
element.setAttribute('data-version', '2.0');

// Checking existence
if (element.dataset.enableCache === 'true') {
    // Enable caching logic
}

// Deleting data attributes
delete element.dataset.newFeature;
</script>

CSS Styling with Data Attributes

<style>
/* Attribute selectors */
[data-status="active"] {
    background-color: #2ecc71;
    color: white;
}

[data-status="inactive"] {
    background-color: #95a5a6;
}

[data-priority="high"] {
    border-left: 4px solid #e74c3c;
}

/* Display data attribute value */
[data-tooltip]:hover::after {
    content: attr(data-tooltip);
    position: absolute;
    background: #333;
    color: white;
    padding: 5px 10px;
    border-radius: 4px;
}

/* Wildcard matching */
[data-theme*="dark"] {
    background-color: #2c3e50;
    color: #ecf0f1;
}
</style>

<span data-status="active">Online</span>
<span data-status="inactive">Offline</span>
<div data-priority="high">Urgent Task</div>
<button data-tooltip="Click to save">Save</button>

Common Use Cases

<!-- Toggle functionality -->
<button data-toggle="modal" data-target="#loginModal">Login</button>

<!-- Sorting and filtering -->
<table id="products">
    <tr data-sortable="true" data-sort-key="name">
        <td data-value="Apple">Apple</td>
        <td data-value="1.50">£1.50</td>
    </tr>
</table>

<!-- Analytics tracking -->
<a href="/products"
   data-track-event="click"
   data-track-category="navigation"
   data-track-label="products-link">
    View Products
</a>

<!-- Form validation messages -->
<input type="email"
       data-error-required="Email is required"
       data-error-invalid="Please enter a valid email">

<!-- Internationalisation -->
<span data-i18n="welcome.message">Welcome!</span>

Accessibility Attributes

Key Concepts

ARIA (Accessible Rich Internet Applications) attributes enhance accessibility for users with disabilities. They provide semantic information about elements, their states, and relationships to assistive technologies like screen readers.

ARIA Roles

<!-- Landmark roles -->
<div role="banner">Site header content</div>
<div role="navigation">Navigation links</div>
<div role="main">Main content</div>
<div role="complementary">Sidebar content</div>
<div role="contentinfo">Footer content</div>
<div role="search">Search form</div>

<!-- Widget roles -->
<div role="button" tabindex="0">Custom Button</div>
<div role="checkbox" aria-checked="false" tabindex="0">Option</div>
<div role="dialog" aria-labelledby="dialog-title">Modal content</div>
<div role="tablist">
    <div role="tab" aria-selected="true">Tab 1</div>
    <div role="tab" aria-selected="false">Tab 2</div>
</div>
<div role="tabpanel">Tab content</div>
<ul role="menu">
    <li role="menuitem">Menu Item</li>
</ul>
<div role="alert">Important message</div>
<div role="status">Status update</div>
<div role="progressbar" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100">
    Loading...
</div>

Common ARIA Attributes

Attribute Description Example
aria-label Accessible name <button aria-label="Close">X</button>
aria-labelledby Reference to labelling element <div aria-labelledby="title-id">
aria-describedby Reference to description <input aria-describedby="help-text">
aria-hidden Hide from assistive tech <span aria-hidden="true">★</span>
aria-expanded Expandable state <button aria-expanded="false">
aria-pressed Toggle button state <button aria-pressed="true">
aria-selected Selection state <li aria-selected="true">
aria-checked Checkbox state <div aria-checked="mixed">
aria-disabled Disabled state <button aria-disabled="true">
aria-required Required field <input aria-required="true">
aria-invalid Validation state <input aria-invalid="true">
aria-live Live region updates <div aria-live="polite">
aria-atomic Announce entire region <div aria-atomic="true">
aria-busy Loading state <div aria-busy="true">
aria-current Current item <a aria-current="page">
aria-haspopup Has popup <button aria-haspopup="menu">
aria-controls Controls another element <button aria-controls="panel-id">
aria-owns Parent-child relationship <div aria-owns="child-id">

Examples

Accessible Navigation

<nav aria-label="Main navigation">
    <ul role="menubar">
        <li role="none">
            <a role="menuitem" href="/" aria-current="page">Home</a>
        </li>
        <li role="none">
            <button role="menuitem" aria-haspopup="true" aria-expanded="false">
                Products
            </button>
            <ul role="menu" aria-label="Products submenu">
                <li role="none">
                    <a role="menuitem" href="/products/new">New Arrivals</a>
                </li>
                <li role="none">
                    <a role="menuitem" href="/products/sale">Sale</a>
                </li>
            </ul>
        </li>
    </ul>
</nav>

Accessible Modal Dialog

<button aria-haspopup="dialog" aria-controls="modal">Open Modal</button>

<div id="modal"
     role="dialog"
     aria-modal="true"
     aria-labelledby="modal-title"
     aria-describedby="modal-desc"
     hidden>
    <h2 id="modal-title">Confirm Action</h2>
    <p id="modal-desc">Are you sure you want to proceed with this action?</p>
    <button>Confirm</button>
    <button aria-label="Close modal">Cancel</button>
</div>

Accessible Form

<form aria-labelledby="form-title">
    <h2 id="form-title">Contact Us</h2>

    <div>
        <label for="name">Name <span aria-hidden="true">*</span></label>
        <input type="text" id="name"
               aria-required="true"
               aria-describedby="name-hint">
        <span id="name-hint" class="hint">Enter your full name</span>
    </div>

    <div>
        <label for="email">Email <span aria-hidden="true">*</span></label>
        <input type="email" id="email"
               aria-required="true"
               aria-invalid="false"
               aria-describedby="email-error">
        <span id="email-error" class="error" role="alert" hidden>
            Please enter a valid email address
        </span>
    </div>

    <div>
        <label for="message">Message</label>
        <textarea id="message"
                  aria-describedby="message-count"></textarea>
        <span id="message-count" aria-live="polite">
            0/500 characters
        </span>
    </div>

    <button type="submit">
        <span aria-hidden="true">📧</span>
        Send Message
    </button>
</form>

Live Regions

<!-- Polite announcements (wait for idle) -->
<div aria-live="polite" aria-atomic="true" id="status">
    <!-- Dynamic status updates -->
</div>

<!-- Assertive announcements (immediate) -->
<div aria-live="assertive" role="alert" id="errors">
    <!-- Error messages -->
</div>

<!-- Loading indicator -->
<div aria-busy="true" aria-live="polite">
    <span role="status">Loading results...</span>
</div>

Accessible Tabs

<div class="tabs">
    <div role="tablist" aria-label="Content sections">
        <button role="tab"
                id="tab-1"
                aria-selected="true"
                aria-controls="panel-1">
            Overview
        </button>
        <button role="tab"
                id="tab-2"
                aria-selected="false"
                aria-controls="panel-2"
                tabindex="-1">
            Details
        </button>
        <button role="tab"
                id="tab-3"
                aria-selected="false"
                aria-controls="panel-3"
                tabindex="-1">
            Reviews
        </button>
    </div>

    <div role="tabpanel"
         id="panel-1"
         aria-labelledby="tab-1">
        Overview content...
    </div>

    <div role="tabpanel"
         id="panel-2"
         aria-labelledby="tab-2"
         hidden>
        Details content...
    </div>

    <div role="tabpanel"
         id="panel-3"
         aria-labelledby="tab-3"
         hidden>
        Reviews content...
    </div>
</div>

Meta Tags and SEO

Key Concepts

Meta tags provide metadata about HTML documents. They inform browsers, search engines, and social media platforms about page content, behaviour, and presentation, directly impacting SEO and user experience.

Essential Meta Tags

<!DOCTYPE html>
<html lang="en-GB">
<head>
    <!-- Character encoding (must be within first 1024 bytes) -->
    <meta charset="UTF-8">

    <!-- Viewport for responsive design -->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

    <!-- Page title (50-60 characters) -->
    <title>Page Title | Brand Name</title>

    <!-- Meta description (150-160 characters) -->
    <meta name="description" content="Concise description of page content for search engine results. Include primary keywords naturally.">

    <!-- Keywords (less important for SEO now) -->
    <meta name="keywords" content="keyword1, keyword2, keyword3">

    <!-- Author -->
    <meta name="author" content="Author Name">

    <!-- Robots directives -->
    <meta name="robots" content="index, follow">

    <!-- Canonical URL -->
    <link rel="canonical" href="https://example.com/page">

    <!-- Language alternatives -->
    <link rel="alternate" hreflang="en-GB" href="https://example.com/en-gb/page">
    <link rel="alternate" hreflang="en-US" href="https://example.com/en-us/page">
    <link rel="alternate" hreflang="x-default" href="https://example.com/page">
</head>
</html>

Open Graph (Social Media)

<!-- Basic Open Graph -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://example.com/page">
<meta property="og:title" content="Page Title">
<meta property="og:description" content="Description for social media sharing">
<meta property="og:image" content="https://example.com/images/og-image.jpg">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt" content="Image description">
<meta property="og:site_name" content="Site Name">
<meta property="og:locale" content="en_GB">

<!-- Article-specific -->
<meta property="og:type" content="article">
<meta property="article:published_time" content="2025-01-15T09:00:00Z">
<meta property="article:modified_time" content="2025-01-16T10:30:00Z">
<meta property="article:author" content="https://example.com/author">
<meta property="article:section" content="Technology">
<meta property="article:tag" content="HTML5">

Twitter Cards

<!-- Summary card -->
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@username">
<meta name="twitter:creator" content="@author">
<meta name="twitter:title" content="Page Title">
<meta name="twitter:description" content="Description for Twitter">
<meta name="twitter:image" content="https://example.com/images/twitter-card.jpg">
<meta name="twitter:image:alt" content="Image description">

<!-- Large image card -->
<meta name="twitter:card" content="summary_large_image">

Technical Meta Tags

<!-- Refresh/redirect -->
<meta http-equiv="refresh" content="5;url=https://example.com/new-page">

<!-- Content Security Policy -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'">

<!-- Cache control -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

<!-- Theme colour (mobile browsers) -->
<meta name="theme-color" content="#3498db">

<!-- Mobile app capable -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="App Name">

<!-- Disable telephone number detection -->
<meta name="format-detection" content="telephone=no">

Favicon and Icons

<!-- Standard favicon -->
<link rel="icon" type="image/x-icon" href="/favicon.ico">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">

<!-- Apple touch icons -->
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">

<!-- Android/Chrome -->
<link rel="manifest" href="/site.webmanifest">
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#3498db">

<!-- Microsoft tiles -->
<meta name="msapplication-TileColor" content="#3498db">
<meta name="msapplication-config" content="/browserconfig.xml">

Structured Data (JSON-LD)

<script type="application/ld+json">
{
    "@context": "https://schema.org",
    "@type": "Article",
    "headline": "Article Title",
    "description": "Article description",
    "image": "https://example.com/image.jpg",
    "author": {
        "@type": "Person",
        "name": "Author Name"
    },
    "publisher": {
        "@type": "Organisation",
        "name": "Publisher Name",
        "logo": {
            "@type": "ImageObject",
            "url": "https://example.com/logo.png"
        }
    },
    "datePublished": "2025-01-15",
    "dateModified": "2025-01-16"
}
</script>

Common Document Structure Patterns

Basic HTML5 Template

<!DOCTYPE html>
<html lang="en-GB">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Page description here">
    <title>Page Title | Site Name</title>
    <link rel="stylesheet" href="styles.css">
</head>
<body>
    <header>
        <h1>Site Name</h1>
        <nav aria-label="Main navigation">
            <ul>
                <li><a href="/">Home</a></li>
                <li><a href="/about">About</a></li>
            </ul>
        </nav>
    </header>

    <main>
        <h2>Page Heading</h2>
        <p>Content goes here...</p>
    </main>

    <footer>
        <p>&copy; 2025 Site Name</p>
    </footer>

    <script src="scripts.js"></script>
</body>
</html>

Blog Post Template

<!DOCTYPE html>
<html lang="en-GB">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="description" content="Brief summary of the article">
    <meta name="author" content="Author Name">

    <!-- Open Graph -->
    <meta property="og:type" content="article">
    <meta property="og:title" content="Article Title">
    <meta property="og:description" content="Article description">
    <meta property="og:image" content="https://example.com/image.jpg">

    <title>Article Title | Blog Name</title>
    <link rel="canonical" href="https://example.com/article-slug">
</head>
<body>
    <header>
        <nav aria-label="Main navigation">
            <!-- Site navigation -->
        </nav>
    </header>

    <main>
        <article>
            <header>
                <h1>Article Title</h1>
                <p class="meta">
                    By <a rel="author" href="/author/name">Author Name</a>
                    on <time datetime="2025-01-15">15 January 2025</time>
                </p>
            </header>

            <section>
                <p>Introduction paragraph...</p>
            </section>

            <section>
                <h2>Section Heading</h2>
                <p>Content...</p>

                <figure>
                    <img src="image.jpg" alt="Description" loading="lazy">
                    <figcaption>Figure 1: Caption text</figcaption>
                </figure>
            </section>

            <footer>
                <p>Tags: <a href="/tag/html5">HTML5</a>, <a href="/tag/web">Web</a></p>
            </footer>
        </article>

        <aside>
            <h2>Related Articles</h2>
            <ul>
                <li><a href="/related-1">Related Article 1</a></li>
                <li><a href="/related-2">Related Article 2</a></li>
            </ul>
        </aside>

        <section aria-labelledby="comments-heading">
            <h2 id="comments-heading">Comments</h2>
            <!-- Comments section -->
        </section>
    </main>

    <footer>
        <p>&copy; 2025 Blog Name</p>
    </footer>
</body>
</html>

Product Page Template

<!DOCTYPE html>
<html lang="en-GB">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Product Name | Shop Name</title>

    <script type="application/ld+json">
    {
        "@context": "https://schema.org",
        "@type": "Product",
        "name": "Product Name",
        "image": "https://example.com/product.jpg",
        "description": "Product description",
        "brand": {
            "@type": "Brand",
            "name": "Brand Name"
        },
        "offers": {
            "@type": "Offer",
            "price": "29.99",
            "priceCurrency": "GBP",
            "availability": "https://schema.org/InStock"
        }
    }
    </script>
</head>
<body>
    <header>
        <!-- Site header and navigation -->
    </header>

    <main>
        <nav aria-label="Breadcrumb">
            <ol>
                <li><a href="/">Home</a></li>
                <li><a href="/category">Category</a></li>
                <li aria-current="page">Product Name</li>
            </ol>
        </nav>

        <article>
            <div class="product-gallery">
                <figure>
                    <picture>
                        <source srcset="product-large.webp" type="image/webp">
                        <img src="product-large.jpg" alt="Product Name">
                    </picture>
                </figure>
            </div>

            <div class="product-info">
                <h1>Product Name</h1>
                <p class="price">£29.99</p>

                <form action="/cart/add" method="POST">
                    <input type="hidden" name="product_id" value="SKU123">

                    <div>
                        <label for="quantity">Quantity:</label>
                        <input type="number" id="quantity" name="quantity"
                               min="1" max="10" value="1">
                    </div>

                    <div>
                        <label for="size">Size:</label>
                        <select id="size" name="size" required>
                            <option value="">Select size</option>
                            <option value="S">Small</option>
                            <option value="M">Medium</option>
                            <option value="L">Large</option>
                        </select>
                    </div>

                    <button type="submit">Add to Cart</button>
                </form>

                <section aria-labelledby="description-heading">
                    <h2 id="description-heading">Description</h2>
                    <p>Product description text...</p>
                </section>
            </div>
        </article>

        <section aria-labelledby="reviews-heading">
            <h2 id="reviews-heading">Customer Reviews</h2>
            <!-- Reviews -->
        </section>
    </main>

    <footer>
        <!-- Footer content -->
    </footer>
</body>
</html>

Quick Reference

HTML5 Doctype and Basic Structure

<!DOCTYPE html>
<html lang="en-GB">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Title</title>
</head>
<body>
    <!-- Content -->
</body>
</html>

Semantic Elements Summary

Element Purpose
<header> Introductory content
<nav> Navigation links
<main> Main content
<article> Self-contained content
<section> Thematic grouping
<aside> Sidebar content
<footer> Footer information
<figure> Media with caption
<figcaption> Caption for figure
<time> Date/time
<mark> Highlighted text
<details> Disclosure widget
<summary> Summary for details
<dialog> Dialog box
<template> HTML template

Form Input Types

Type Description
text Single-line text
email Email address
password Password field
number Numeric input
range Slider
date Date picker
time Time picker
datetime-local Date and time
month Month picker
week Week picker
tel Telephone
url URL
search Search field
color Colour picker
file File upload

Essential ARIA Attributes

Attribute Purpose
aria-label Accessible name
aria-labelledby Label reference
aria-describedby Description reference
aria-hidden Hide from AT
aria-expanded Expanded state
aria-pressed Toggle state
aria-selected Selection state
aria-required Required field
aria-invalid Validation state
aria-live Live updates
aria-current Current item

Common Roles

Role Purpose
banner Site header
navigation Navigation
main Main content
complementary Sidebar
contentinfo Footer
search Search area
button Button
dialog Modal
alert Alert message
tab / tabpanel Tabs
menu / menuitem Menus

Common Issues and Solutions

Issue: Form Validation Not Working

Problem: HTML5 validation is bypassed or not showing error messages.

Solutions:

<!-- Ensure form doesn't have novalidate -->
<form action="/submit" method="POST">
    <!-- NOT: <form novalidate> -->

    <!-- Use correct input types -->
    <input type="email" required>

    <!-- Custom validation with pattern -->
    <input type="text" pattern="[A-Z]{2}[0-9]{6}"
           title="Two letters followed by six numbers">
</form>

<!-- Custom validation messages with JavaScript -->
<script>
const input = document.querySelector('input[type="email"]');
input.addEventListener('invalid', function() {
    this.setCustomValidity('Please enter a valid email address');
});
input.addEventListener('input', function() {
    this.setCustomValidity('');
});
</script>

Issue: Video Not Playing

Problem: Video doesn't play or shows black screen.

Solutions:

<!-- Provide multiple formats -->
<video controls>
    <source src="video.webm" type="video/webm">
    <source src="video.mp4" type="video/mp4">
    <source src="video.ogv" type="video/ogg">
    <p>Your browser doesn't support video.</p>
</video>

<!-- For autoplay, must be muted -->
<video autoplay muted playsinline>
    <source src="video.mp4" type="video/mp4">
</video>

<!-- Check MIME types on server -->
<!-- .htaccess: AddType video/mp4 .mp4 -->

Issue: Responsive Images Not Working

Problem: Picture element not showing correct image.

Solutions:

<!-- Order matters: first match wins -->
<picture>
    <!-- Larger breakpoints first -->
    <source media="(min-width: 1200px)" srcset="large.jpg">
    <source media="(min-width: 768px)" srcset="medium.jpg">
    <!-- Fallback last -->
    <img src="small.jpg" alt="Description">
</picture>

<!-- Always include img as fallback -->
<!-- img is required for picture to work -->

Issue: ARIA Not Being Announced

Problem: Screen readers not announcing ARIA content.

Solutions:

<!-- Use correct aria-live values -->
<div aria-live="polite">Status updates here</div>
<div aria-live="assertive" role="alert">Errors here</div>

<!-- Ensure element exists in DOM before updating -->
<div id="status" aria-live="polite"></div>
<script>
    // Element exists, now update content
    document.getElementById('status').textContent = 'Updated';
</script>

<!-- Don't use aria-hidden on focusable elements -->
<!-- WRONG: -->
<button aria-hidden="true">Hidden Button</button>
<!-- RIGHT: -->
<button hidden>Hidden Button</button>

Issue: Data Attributes Not Accessible in JavaScript

Problem: Cannot read data attributes from JavaScript.

Solutions:

<div id="element" data-user-id="123" data-is-active="true"></div>

<script>
const el = document.getElementById('element');

// Use dataset with camelCase
console.log(el.dataset.userId);    // "123"
console.log(el.dataset.isActive);  // "true"

// NOT: el.dataset['user-id'] or el.dataset.user-id

// Values are always strings
if (el.dataset.isActive === 'true') {
    // Handle boolean
}
const id = parseInt(el.dataset.userId, 10);
</script>

Issue: Canvas Blurry on Retina Displays

Problem: Canvas appears blurry on high-DPI screens.

Solutions:

<canvas id="canvas"></canvas>

<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const dpr = window.devicePixelRatio || 1;

// Set display size
canvas.style.width = '400px';
canvas.style.height = '300px';

// Set actual size in memory
canvas.width = 400 * dpr;
canvas.height = 300 * dpr;

// Scale context
ctx.scale(dpr, dpr);

// Now draw as normal
ctx.fillRect(10, 10, 100, 100);
</script>

Issue: Semantic Elements Not Styled Correctly in Old Browsers

Problem: HTML5 elements not displayed as block in older browsers.

Solutions:

/* Ensure block display for semantic elements */
article, aside, details, figcaption, figure,
footer, header, hgroup, main, menu, nav, section {
    display: block;
}

/* Hidden attribute support */
[hidden] {
    display: none;
}

Issue: Form autocomplete Not Working

Problem: Browser not auto-filling form fields.

Solutions:

<!-- Use correct autocomplete values -->
<input type="text" name="name" autocomplete="name">
<input type="email" name="email" autocomplete="email">
<input type="tel" name="phone" autocomplete="tel">
<input type="text" name="address" autocomplete="street-address">
<input type="text" name="city" autocomplete="address-level2">
<input type="text" name="postcode" autocomplete="postal-code">
<input type="text" name="cc-number" autocomplete="cc-number">

<!-- Group related fields -->
<fieldset>
    <legend>Shipping Address</legend>
    <!-- address fields with autocomplete="shipping ..." -->
</fieldset>

Related Topics

The following topics complement this HTML5 cheatsheet and would help build a more complete understanding of modern web development:

  1. CSS3 - Styling, layouts (Flexbox, Grid), animations, and responsive design techniques that work alongside HTML5 elements

  2. JavaScript DOM Manipulation - Interacting with HTML5 elements, handling events, form validation, and dynamic content updates

  3. Web Accessibility (WCAG) - Comprehensive accessibility guidelines, testing tools, and best practices beyond basic ARIA implementation

  4. Progressive Web Apps (PWA) - Service workers, web manifests, offline support, and native-like web application features

  5. Web Performance Optimisation - Image optimisation, lazy loading, critical rendering path, Core Web Vitals, and caching strategies

  6. SEO Best Practices - On-page optimisation, structured data, content strategy, and search engine ranking factors beyond meta tags