| name | html |
| description | Write semantic, accessible, performant HTML with modern best practices. Use when asked to (1) create HTML pages or documents, (2) write semantic markup, (3) improve accessibility, (4) optimize HTML structure and performance, (5) implement forms, tables, or complex layouts, or when phrases like "HTML page", "web page", "markup", "semantic HTML", "accessibility" appear. |
Expert HTML Development
Write clean, semantic, accessible HTML that follows modern web standards and best practices.
MCP Integration - Context7
CRITICAL: Before writing or editing ANY HTML code, ALWAYS use the Context7 MCP server to check for relevant context.
Context7 provides access to a knowledge base that may contain:
- Project-specific HTML patterns and conventions
- Custom component libraries and templates
- Style guide requirements
- Accessibility standards for the project
- Performance benchmarks and requirements
- Team preferences and coding standards
Workflow:
- Before writing code: Query Context7 for relevant patterns, conventions, or examples
- During editing: Check Context7 for project-specific requirements that might affect your changes
- After writing: Verify your code aligns with any Context7 guidance
Use Context7 to search for topics like:
- "HTML conventions"
- "accessibility requirements"
- "component templates"
- "form patterns"
- "performance standards"
- Specific component or pattern names
Never skip the Context7 check - it ensures your HTML aligns with project standards and leverages existing patterns.
Core Principles
- Semantic first - Use elements for their intended meaning, not just appearance
- Accessibility by default - Every user deserves a great experience
- Progressive enhancement - Start with working HTML, layer on CSS/JS
- Performance matters - Optimize for speed and efficiency
Document Structure
Minimal Valid HTML5 Document
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Page Title - Site Name</title>
<meta name="description" content="Clear, concise page description (150-160 chars)">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header>
<nav aria-label="Main navigation">
</nav>
</header>
<main>
</main>
<footer>
</footer>
<script src="script.js" defer></script>
</body>
</html>
Essential Meta Tags
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Specific, Descriptive Title | Brand</title>
<meta name="description" content="Clear description for search results">
<link rel="canonical" href="https://example.com/page">
<meta property="og:title" content="Title for Social Media">
<meta property="og:description" content="Description for social cards">
<meta property="og:image" content="https://example.com/image.jpg">
<meta property="og:url" content="https://example.com/page">
<meta property="og:type" content="website">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Title for Twitter">
<meta name="twitter:description" content="Description for Twitter">
<meta name="twitter:image" content="https://example.com/image.jpg">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="preload" href="critical-font.woff2" as="font" type="font/woff2" crossorigin>
<meta name="theme-color" content="#000000" media="(prefers-color-scheme: dark)">
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)">
</head>
Semantic HTML Elements
Use the Right Element for the Job
<div class="header">
<div class="nav">
<div class="nav-item">Home</div>
</div>
</div>
<div class="content">
<div class="article">
<div class="title">Article Title</div>
<div class="text">Article content...</div>
</div>
</div>
<header>
<nav aria-label="Main navigation">
<a href="/">Home</a>
</nav>
</header>
<main>
<article>
<h1>Article Title</h1>
<p>Article content...</p>
</article>
</main>
Sectioning Elements
| Element | Purpose | When to Use |
|---|
<header> | Introductory content | Site/section header, not just "top of page" |
<nav> | Navigation links | Primary navigation, table of contents, breadcrumbs |
<main> | Primary content | One per page, skips to main content |
<article> | Self-contained content | Blog posts, news items, forum posts |
<section> | Thematic grouping | Chapters, tabs, themed sections (always has heading) |
<aside> | Tangentially related | Sidebars, pull quotes, related links |
<footer> | Footer content | Site/section footer, not just "bottom of page" |
Heading Hierarchy
<h1>Page Title</h1>
<h2>Main Section</h2>
<h3>Subsection</h3>
<h3>Another Subsection</h3>
<h2>Another Main Section</h2>
<h1>Page Title</h1>
<h4>Skipped h2 and h3</h4>
Accessibility Best Practices
ARIA Labels and Roles
<nav aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav>
<nav aria-label="Footer navigation">
</nav>
<button aria-label="Close dialog">
<svg aria-hidden="true"></svg>
</button>
<img src="decorative.png" alt="" role="presentation">
<span aria-hidden="true">📧</span>
<label for="email">Email Address</label>
<input type="email" id="email" name="email" required>
<label>
Email Address
<input type="email" name="email" required>
</label>
Focus Management
<a href="#main" class="skip-link">Skip to main content</a>
<main id="main" tabindex="-1">
</main>
<div role="button" tabindex="0" onclick="handleClick()" onkeydown="handleKeyPress(event)">
Custom Button
</div>
Alternative Text
<img src="chart.png" alt="Bar chart showing 40% increase in sales from Q1 to Q2 2024">
<img src="decorative-border.png" alt="">
<img src="complex-diagram.png" alt="Network topology diagram" aria-describedby="diagram-desc">
<div id="diagram-desc">
Detailed description of the network topology showing...
</div>
<img src="chart.png" alt="image">
<img src="chart.png" alt="chart.png">
ARIA Live Regions
<div role="status" aria-live="polite" aria-atomic="true">
<span id="status-message">Loading...</span>
</div>
<div role="alert" aria-live="assertive">
Error: Please correct the form errors below.
</div>
Forms
Accessible Form Structure
<form method="post" action="/submit" novalidate>
<fieldset>
<legend>Personal Information</legend>
<label for="name">Full Name</label>
<input
type="text"
id="name"
name="name"
required
aria-required="true"
aria-describedby="name-hint"
autocomplete="name"
>
<small id="name-hint">Enter your first and last name</small>
<label for="email">Email</label>
<input
type="email"
id="email"
name="email"
required
aria-required="true"
autocomplete="email"
aria-invalid="false"
>
<span id="email-error" class="error" role="alert"></span>
<label for="country">Country</label>
<select id="country" name="country" required>
<option value="">Select a country</option>
<optgroup label="North America">
<option value="us">United States</option>
<option value="ca">Canada</option>
</optgroup>
<optgroup label="Europe">
<option value="uk">United Kingdom</option>
<option value="de">Germany</option>
</optgroup>
</select>
<fieldset>
<legend>Preferred Contact Method</legend>
<label>
<input type="radio" name="contact" value="email" checked>
Email
</label>
<label>
<input type="radio" name="contact" value="phone">
Phone
</label>
</fieldset>
<fieldset>
<legend>Newsletter Subscriptions</legend>
<label>
<input type="checkbox" name="newsletters" value="weekly">
Weekly Updates
</label>
<label>
<input type="checkbox" name="newsletters" value="monthly">
Monthly Digest
</label>
</fieldset>
<label for="message">Message</label>
<textarea
id="message"
name="message"
rows="5"
maxlength="500"
aria-describedby="char-count"
></textarea>
<small id="char-count">0 / 500 characters</small>
</fieldset>
<button type="submit">Submit Form</button>
<button type="reset">Clear Form</button>
</form>
HTML5 Input Types
<input type="email" name="email" autocomplete="email">
<input type="tel" name="phone" autocomplete="tel">
<input type="url" name="website">
<input type="number" name="quantity" min="1" max="100" step="1">
<input type="range" name="volume" min="0" max="100" value="50">
<input type="date" name="dob" autocomplete="bday">
<input type="time" name="appointment">
<input type="datetime-local" name="event-time">
<input type="color" name="theme-color" value="#000000">
<input type="file" name="upload" accept="image/*,.pdf" multiple>
<input type="search" name="query" autocomplete="off">
Input Attributes for Better UX
<input type="text" name="given-name" autocomplete="given-name">
<input type="text" name="family-name" autocomplete="family-name">
<input type="text" name="address-line1" autocomplete="address-line1">
<input type="text" name="postal-code" autocomplete="postal-code">
<input
type="text"
name="username"
pattern="[a-zA-Z0-9_]{3,16}"
title="Username must be 3-16 characters, letters, numbers, and underscores only"
>
<input type="text" name="search" autofocus>
<input type="text" inputmode="numeric" name="credit-card">
<input type="text" inputmode="decimal" name="price">
<input type="text" inputmode="email" name="email">
Tables
Accessible Data Tables
<table>
<caption>Quarterly Sales Report for 2024</caption>
<thead>
<tr>
<th scope="col">Quarter</th>
<th scope="col">Revenue</th>
<th scope="col">Growth</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Q1</th>
<td>$1.2M</td>
<td>+5%</td>
</tr>
<tr>
<th scope="row">Q2</th>
<td>$1.5M</td>
<td>+25%</td>
</tr>
</tbody>
<tfoot>
<tr>
<th scope="row">Total</th>
<td>$2.7M</td>
<td>+15%</td>
</tr>
</tfoot>
</table>
<table>
<caption>Course Schedule by Instructor and Day</caption>
<thead>
<tr>
<th scope="col">Instructor</th>
<th scope="col">Monday</th>
<th scope="col">Tuesday</th>
<th scope="col">Wednesday</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">Dr. Smith</th>
<td headers="smith monday">Biology 101</td>
<td headers="smith tuesday">Biology 201</td>
<td headers="smith wednesday">Lab</td>
</tr>
</tbody>
</table>
Lists
Choosing the Right List Type
<ul>
<li>Apples</li>
<li>Bananas</li>
<li>Oranges</li>
</ul>
<ol>
<li>Preheat oven to 350°F</li>
<li>Mix dry ingredients</li>
<li>Add wet ingredients</li>
<li>Bake for 25 minutes</li>
</ol>
<dl>
<dt>HTML</dt>
<dd>HyperText Markup Language, the standard markup language for web pages.</dd>
<dt>CSS</dt>
<dd>Cascading Style Sheets, used to style HTML elements.</dd>
</dl>
<ul>
<li>Fruits
<ul>
<li>Tropical
<ul>
<li>Mango</li>
<li>Papaya</li>
</ul>
</li>
<li>Citrus
<ul>
<li>Orange</li>
<li>Lemon</li>
</ul>
</li>
</ul>
</li>
</ul>
Performance Optimization
Image Optimization
<img
src="image-800w.jpg"
srcset="
image-400w.jpg 400w,
image-800w.jpg 800w,
image-1200w.jpg 1200w,
image-1600w.jpg 1600w
"
sizes="(max-width: 600px) 100vw, (max-width: 1200px) 50vw, 800px"
alt="Descriptive alt text"
loading="lazy"
decoding="async"
width="800"
height="600"
>
<picture>
<source media="(max-width: 799px)" srcset="mobile-image.jpg">
<source media="(min-width: 800px)" srcset="desktop-image.jpg">
<img src="fallback-image.jpg" alt="Descriptive alt text">
</picture>
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Descriptive alt text">
</picture>
<img src="below-fold-image.jpg" alt="Alt text" loading="lazy">
<img src="hero-image.jpg" alt="Alt text" loading="eager" fetchpriority="high">
Resource Loading Strategies
<head>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://analytics.example.com">
<link rel="preload" href="critical-font.woff2" as="font" type="font/woff2" crossorigin>
<link rel="preload" href="hero-image.jpg" as="image">
<link rel="preload" href="critical-styles.css" as="style">
<link rel="prefetch" href="/next-page.html">
<link rel="prefetch" href="next-page-image.jpg" as="image">
</head>
<body>
<script src="analytics.js" defer></script>
<script src="widget.js" async></script>
<script type="module" src="app.js"></script>
<style>
</style>
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">
<noscript><link rel="stylesheet" href="non-critical.css"></noscript>
</body>
HTML Size Optimization
<div class="container">
<p>
Some text here
</p>
</div>
<div class="container"><p>Some text here</p></div>
<div id="unused-id" class="unused-class"></div>
<div></div>
<p style="color: red;"><span style="font-weight: bold;">Text</span></p>
<p class="error-text">Text</p>
Modern HTML Features
Details and Summary (Native Disclosure)
<details>
<summary>Click to expand</summary>
<p>Hidden content that can be toggled.</p>
</details>
<details open>
<summary>FAQ Question</summary>
<p>Answer to the question.</p>
</details>
Dialog Element (Native Modal)
<dialog id="myDialog">
<form method="dialog">
<h2>Dialog Title</h2>
<p>Dialog content goes here.</p>
<button value="cancel">Cancel</button>
<button value="confirm" autofocus>Confirm</button>
</form>
</dialog>
<button onclick="document.getElementById('myDialog').showModal()">
Open Dialog
</button>
Data Attributes
<article data-post-id="12345" data-author="jane-doe" data-category="tech">
<h2>Article Title</h2>
</article>
Template Element
<template id="item-template">
<li class="item">
<h3 class="item-title"></h3>
<p class="item-description"></p>
</li>
</template>
<script>
const template = document.getElementById('item-template');
const clone = template.content.cloneNode(true);
</script>
Content Embedding
Videos
<video
controls
width="640"
height="360"
poster="video-thumbnail.jpg"
preload="metadata"
>
<source src="video.webm" type="video/webm">
<source src="video.mp4" type="video/mp4">
<track
kind="subtitles"
src="subtitles-en.vtt"
srclang="en"
label="English"
>
<track
kind="captions"
src="captions-en.vtt"
srclang="en"
label="English CC"
default
>
<p>Your browser doesn't support HTML5 video.
<a href="video.mp4">Download the video</a> instead.</p>
</video>
<iframe
width="560"
height="315"
src="https://www.youtube.com/embed/VIDEO_ID"
title="Video Title for Accessibility"
frameborder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowfullscreen
loading="lazy"
></iframe>
Audio
<audio controls preload="metadata">
<source src="audio.mp3" type="audio/mpeg">
<source src="audio.ogg" type="audio/ogg">
<p>Your browser doesn't support HTML5 audio.
<a href="audio.mp3">Download the audio</a> instead.</p>
</audio>
Iframes
<iframe
src="https://example.com/embed"
title="Descriptive title for screen readers"
width="600"
height="400"
loading="lazy"
sandbox="allow-scripts allow-same-origin"
></iframe>
Validation and Quality
HTML Validation Checklist
Common HTML Mistakes to Avoid
<a href="#"><div>Link content</div></a>
<a href="#" style="display: block"><div>Link content</div></a>
<p>First paragraph</p>
<br><br>
<p>Second paragraph</p>
<p>First paragraph</p>
<p style="margin-top: 2rem;">Second paragraph</p>
<div>
<div>
<div>
<p>Content</p>
</div>
</div>
</div>
<p>Content</p>
<div></div>
<span></span>
<table>
<tr>
<td>Sidebar</td>
<td>Main content</td>
</tr>
</table>
<div class="layout">
<aside>Sidebar</aside>
<main>Main content</main>
</div>
Security Best Practices
Input Sanitization Context
<div>{{userInput}}</div>
<div><script>alert('safe')</script></div>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' https://trusted.cdn.com">
External Resources
<script
src="https://cdn.example.com/library.js"
integrity="sha384-HASH_HERE"
crossorigin="anonymous"
></script>
<a href="https://external-site.com" target="_blank" rel="noopener noreferrer">
External Link
</a>
Progressive Enhancement
Build from HTML Up
<details>
<summary>Expandable Section</summary>
<p>Content revealed when expanded.</p>
</details>
<style>
details { border: 1px solid #ccc; padding: 1rem; }
summary { cursor: pointer; font-weight: bold; }
</style>
<script>
document.querySelectorAll('details').forEach(detail => {
detail.addEventListener('toggle', () => {
if (detail.open) {
}
});
});
</script>
Tools and Workflow
Recommended Tools
HTML in Build Pipelines
npx html-validate src/**/*.html
npx html-minifier --collapse-whitespace --remove-comments input.html -o output.html
npx pa11y http://localhost:3000
Quick Reference
Common Character Entities
| Character | Entity | Numeric |
|---|
| < | < | < |
| > | > | > |
| & | & | & |
| " | " | " |
| ' | ' | ' |
| © | © | © |
| ® | ® | ® |
| ™ | ™ | ™ |
| non-breaking space | |   |
| — (em dash) | — | — |
| – (en dash) | – | – |
Global Attributes
Available on all HTML elements:
id - Unique identifier
class - CSS class names (space-separated)
style - Inline CSS styles
title - Advisory information (tooltip)
lang - Language of element content
dir - Text directionality (ltr, rtl, auto)
hidden - Hide element
tabindex - Tab order (-1, 0, positive numbers)
contenteditable - Make element editable
data-* - Custom data attributes
draggable - Enable drag and drop
spellcheck - Enable spell checking
Best Practices Summary
- Always check Context7 MCP before writing/editing code - Leverage project-specific patterns and requirements
- Always use semantic HTML - Choose elements based on meaning, not appearance
- Validate your HTML - Use W3C validator to catch errors
- Prioritize accessibility - Use ARIA attributes, alt text, and keyboard navigation
- Optimize for performance - Lazy load images, defer scripts, minimize HTML
- Use progressive enhancement - Start with HTML, layer on CSS and JavaScript
- Keep it simple - Don't over-engineer with unnecessary divs and complexity
- Test across browsers - Ensure compatibility with all major browsers
- Think mobile-first - Design for small screens, enhance for larger ones
- Use meaningful names - IDs and classes should describe purpose, not appearance
- Comment sparingly - Code should be self-documenting, comments for complex logic only