|$ curl https://forge-ai.dev/api/markdown?path=docs/html/elements
$cat docs/html-elements.md
updated Last week·45 min read·published

HTML Elements

HTMLElementsReferenceBeginner
Introduction

HTML elements are the fundamental building blocks of web pages. Each element is defined by a tag name, optional attributes, and optional content. Elements provide structure, semantics, and interactivity to documents.

info

Element names are case-insensitive, but always use lowercase. Attribute values should be quoted. Use double quotes for consistency across your project.
Element Anatomy

Every HTML element follows a consistent structure composed of an opening tag, optional attributes, content, and a closing tag:

anatomy.html
HTML
1<opening-tag attributes>content</closing-tag>
2
3<!-- Concrete example: -->
4<a href="https://example.com" class="link">
5 Click here
6</a>
7
8<!-- Void elements have no closing tag or content: -->
9<img src="photo.jpg" alt="Photo" />

The opening tag contains the element name and any attributes. Attributes provide additional configuration — common ones include class, id, style, and data-*. The content is what appears between the opening and closing tags. Void elements (like <img>, <br>, <hr>) cannot have children.

Content Models

The HTML specification categorizes elements into content models that define what kind of content an element can contain. Understanding these models is essential for writing valid, semantic markup.

Content ModelDescriptionExamples
FlowMost elements that appear in the body. The broadest category.<div>, <p>, <section>, <h1>
PhrasingInline-level text markup. Can contain only other phrasing elements.<span>, <strong>, <a>, <code>
SectioningCreates sections in the document outline.<section>, <article>, <nav>, <aside>
HeadingDefines headings for sections.<h1>–<h6>, <hgroup>
InteractiveElements designed for user interaction.<button>, <a>, <details>, <input>
EmbeddedElements that embed external resources.<img>, <video>, <audio>, <iframe>
PalpableElements that render visible content (non-empty).Most flow and phrasing elements
MetadataElements that describe the document itself.<title>, <meta>, <link>, <style>

best practice

Nesting rules matter. For example, a <p> element cannot contain block-level elements like <div> or <section>. Always check the content model of parent elements before nesting.

Content models are hierarchical. Phrasing content is a subset of flow content. Sectioning and heading content are also flow content. An element belongs to one or more categories, which determines where it may be used and what it may contain.

nesting.html
HTML
1<!-- Valid: phrasing inside flow -->
2<div>
3 <p>This is <strong>valid</strong> nesting.</p>
4</div>
5
6<!-- Invalid: block inside phrasing -->
7<p>
8 <div>This is invalid.</div>
9</p>
10
11<!-- Valid: interactive inside phrasing -->
12<p>
13 Click <a href="/">here</a> for more.
14</p>
Sectioning Elements

Sectioning elements define the structure and outline of a document. They give semantic meaning to different parts of a page, improving accessibility and SEO.

ElementPurposeUsage
<header>Introductory content or navigation aidsTop of page or section
<nav>Navigation linksPrimary site navigation
<main>Dominant content of the documentOne per page
<section>Generic standalone sectionThematic grouping
<article>Self-contained compositionBlog posts, forum posts
<aside>Tangentially related contentSidebars, pull quotes
<footer>Footer for nearest sectioning rootBottom of page or section
<address>Contact informationAuthor or organization contact
sectioning.html
HTML
1<body>
2 <header>
3 <nav>
4 <a href="/">Home</a>
5 <a href="/blog">Blog</a>
6 <a href="/contact">Contact</a>
7 </nav>
8 </header>
9
10 <main>
11 <article>
12 <header>
13 <hgroup>
14 <h1>Article Title</h1>
15 <p>Published on <time datetime="2026-07-07">July 7, 2026</time></p>
16 </hgroup>
17 </header>
18
19 <section>
20 <h2>Introduction</h2>
21 <p>This is the first section of the article.</p>
22 </section>
23
24 <section>
25 <h2>Details</h2>
26 <p>More detailed content goes here.</p>
27 </section>
28
29 <footer>
30 <address>
31 Written by <a href="mailto:author@example.com">Jane Doe</a>
32 </address>
33 </footer>
34 </article>
35
36 <aside>
37 <h3>Related Articles</h3>
38 <ul>
39 <li><a href="/article-2">How to Use HTML</a></li>
40 <li><a href="/article-3">CSS Basics</a></li>
41 </ul>
42 </aside>
43 </main>
44
45 <footer>
46 <p>&copy; 2026 Example Corp</p>
47 </footer>
48</body>
🔥

pro tip

The <hgroup> element groups a heading with its subheadings. It was re-added in HTML 5.3 and is useful for hiding secondary headings from the document outline while keeping them visible on the page.

Live preview of a sectioning layout:

preview
Block Elements

Block-level elements occupy the full width of their parent container and start on a new line. They are used for structural layout and grouping content.

ElementPurpose
<div>Generic container (no semantic meaning)
<p>Paragraph of text
<ul> / <ol>Unordered and ordered lists
<dl> / <dt> / <dd>Description list (terms and definitions)
<pre>Preformatted text (preserves whitespace)
<blockquote>Block quotation
<figure> / <figcaption>Self-contained content with caption
<hr>Thematic break (horizontal rule)

Lists are one of the most common block elements. Unordered lists use bullet points, ordered lists use numbers, and description lists pair terms with definitions:

lists.html
HTML
1<!-- Unordered list -->
2<ul>
3 <li>Apples</li>
4 <li>Bananas</li>
5 <li>Cherries</li>
6</ul>
7
8<!-- Ordered list with custom numbering -->
9<ol type="A" start="3">
10 <li>First step</li>
11 <li>Second step</li>
12 <li>Third step</li>
13</ol>
14
15<!-- Description list -->
16<dl>
17 <dt>HTML</dt>
18 <dd>HyperText Markup Language — the standard language for creating web pages.</dd>
19 <dt>CSS</dt>
20 <dd>Cascading Style Sheets — used for styling HTML documents.</dd>
21</dl>

Figures group media with optional captions. Blockquotes represent quoted content from external sources:

misc-block.html
HTML
1<figure>
2 <img src="diagram.png" alt="Architecture diagram showing client-server flow">
3 <figcaption>Figure 1: System architecture overview</figcaption>
4</figure>
5
6<blockquote cite="https://example.com/source">
7 <p>The best way to predict the future is to invent it.</p>
8 <footer>— <cite>Alan Kay</cite></footer>
9</blockquote>
10
11<pre><code>function hello() {
12 console.log("Hello, World!");
13}</code></pre>

best practice

Use <div> only when no other semantic element is appropriate. Prefer <section>, <article>, <nav>, or <aside> for meaningful regions. Use <figure> for images, diagrams, and code snippets that benefit from a caption.
Inline Elements

Inline elements flow within text without breaking the line. They are used to semantically mark up parts of a sentence or phrase.

ElementPurposeExample
<span>Generic inline container<span class="icon">★</span>
<a>Hyperlink anchor<a href="/">Home</a>
<strong>Strong importance (bold)<strong>Warning!</strong>
<em>Emphasis (italic)<em>really</em> important
<code>Inline code fragment<code>npm start</code>
<kbd>Keyboard inputPress <kbd>Ctrl+S</kbd>
<samp>Sample output<samp>Error 404</samp>
<abbr>Abbreviation / acronym<abbr title="World Wide Web">WWW</abbr>
<cite>Title of a work<cite>The Art of War</cite>
<q>Inline quotation<q>Hello World</q>
<sub> / <sup>Subscript / SuperscriptH<sub>2</sub>O, 10<sup>3</sup>
<time>Machine-readable date/time<time datetime="2026-07-07">Today</time>
<mark>Highlighted text<mark>important</mark>
<bdo>Bidirectional text override<bdo dir="rtl">مرحبا</bdo>
<small>Side comments / fine print<small>Terms apply</small>
<dfn>Defining instance of a term<dfn>HTML</dfn> is a language
inline.html
HTML
1<p>
2 The <abbr title="HyperText Markup Language">HTML</abbr>
3 specification defines the <code><strong&gt;</code> element
4 for <strong>strong importance</strong> and the
5 <code><em&gt;</code> element for <em>emphasis</em>.
6</p>
7
8<p>
9 Press <kbd>Ctrl</kbd> + <kbd>C</kbd> to copy.
10 The terminal outputs: <samp>Copied 1 file</samp>
11</p>
12
13<p>
14 Chemical formula: H<sub>2</sub>O
15 Mathematical expression: 10<sup>3</sup> = 1000
16</p>
17
18<p>
19 The <cite>HTML Living Standard</cite> is maintained by the
20 <abbr title="World Wide Web Consortium">W3C</abbr>.
21 Published <time datetime="2026-07-07">today</time>.
22</p>
23
24<p>
25 Search results for "semantic <mark>HTML</mark>":
26 <q>Semantic HTML improves accessibility.</q>
27</p>
Embedded Elements

Embedded elements allow you to integrate external resources — images, video, audio, and other documents — into your web pages.

ElementPurpose
<img>Embeds an image
<picture>Responsive image with multiple sources
<source>Specifies multiple media sources
<video>Embeds video content
<audio>Embeds audio content
<iframe>Embeds another HTML document
<canvas>Drawing surface for scripts
<svg>Scalable Vector Graphics

Images are the most common embedded element. Always include descriptive alt text for accessibility. Use <picture> for responsive images that serve different formats based on screen size or capabilities:

images.html
HTML
1<!-- Basic image with alt text -->
2<img
3 src="photo.jpg"
4 alt="A sunset over the ocean with silhouetted palm trees"
5 width="800"
6 height="600"
7 loading="lazy"
8 decoding="async"
9/>
10
11<!-- Responsive image with picture element -->
12<picture>
13 <source
14 srcset="photo.avif"
15 type="image/avif"
16 media="(min-width: 800px)"
17 />
18 <source
19 srcset="photo.webp"
20 type="image/webp"
21 />
22 <img
23 src="photo.jpg"
24 alt="Sunset over the ocean"
25 width="800"
26 height="600"
27 loading="lazy"
28 />
29</picture>

Video and audio elements provide native playback controls without requiring third-party plugins:

media.html
HTML
1<!-- Video with controls -->
2<video
3 controls
4 width="640"
5 height="360"
6 poster="thumbnail.jpg"
7 preload="metadata"
8>
9 <source src="video.mp4" type="video/mp4" />
10 <source src="video.webm" type="video/webm" />
11 <track
12 kind="subtitles"
13 src="subtitles.vtt"
14 srclang="en"
15 label="English"
16 />
17 <p>Your browser does not support video.</p>
18</video>
19
20<!-- Audio with controls -->
21<audio controls preload="none">
22 <source src="podcast.mp3" type="audio/mpeg" />
23 <source src="podcast.ogg" type="audio/ogg" />
24 <p>Your browser does not support audio.</p>
25</audio>
26
27<!-- Inline SVG -->
28<svg viewBox="0 0 100 100" width="50" height="50">
29 <circle cx="50" cy="50" r="40" fill="#00FF41" />
30 <text x="50" y="55" text-anchor="middle" fill="#000" font-size="20">SVG</text>
31</svg>

warning

Always include loading="lazy" on images below the fold to defer loading until the user scrolls near them. Use width and height attributes to prevent Cumulative Layout Shift (CLS).

Live preview of an inline SVG and an image placeholder:

preview
Forms

Forms are the primary way users interact with web applications. They collect and submit user input to servers for processing.

ElementPurpose
<form>Container for form controls
<input>Versatile input control (many types)
<textarea>Multi-line text input
<select> / <option>Dropdown selection
<button>Clickable button
<label>Label for a form control
<fieldset> / <legend>Groups related form controls with caption
<datalist>Predefined options for autocomplete
<output>Result of a calculation
<progress>Progress indicator
<meter>Scalar measurement gauge

Input types define the kind of data expected. HTML5 introduced many specialized input types for better user experience on different devices:

form.html
HTML
1<form action="/submit" method="POST" novalidate>
2 <fieldset>
3 <legend>Personal Information</legend>
4
5 <label for="name">Full Name</label>
6 <input
7 type="text"
8 id="name"
9 name="name"
10 required
11 minlength="2"
12 maxlength="100"
13 placeholder="Jane Doe"
14 />
15
16 <label for="email">Email Address</label>
17 <input
18 type="email"
19 id="email"
20 name="email"
21 required
22 placeholder="jane@example.com"
23 />
24
25 <label for="age">Age</label>
26 <input
27 type="number"
28 id="age"
29 name="age"
30 min="1"
31 max="150"
32 step="1"
33 />
34
35 <label for="dob">Date of Birth</label>
36 <input type="date" id="dob" name="dob" />
37
38 <label for="color">Favorite Color</label>
39 <input type="color" id="color" name="color" value="#00FF41" />
40
41 <label for="website">Website</label>
42 <input
43 type="url"
44 id="website"
45 name="website"
46 placeholder="https://example.com"
47 />
48 </fieldset>
49
50 <fieldset>
51 <legend>Additional Details</legend>
52
53 <label for="bio">Biography</label>
54 <textarea
55 id="bio"
56 name="bio"
57 rows="4"
58 maxlength="500"
59 placeholder="Tell us about yourself..."
60 ></textarea>
61
62 <label for="country">Country</label>
63 <select id="country" name="country">
64 <optgroup label="North America">
65 <option value="us">United States</option>
66 <option value="ca">Canada</option>
67 </optgroup>
68 <optgroup label="Europe">
69 <option value="uk">United Kingdom</option>
70 <option value="de">Germany</option>
71 <option value="fr">France</option>
72 </optgroup>
73 </select>
74
75 <label for="browser">Preferred Browser</label>
76 <input list="browsers" id="browser" name="browser" />
77 <datalist id="browsers">
78 <option value="Chrome" />
79 <option value="Firefox" />
80 <option value="Safari" />
81 <option value="Edge" />
82 </datalist>
83 </fieldset>
84
85 <button type="submit">Submit Form</button>
86 <button type="reset">Reset</button>
87</form>

Progress and meter elements provide native visual indicators:

progress.html
HTML
1<!-- Progress bar -->
2<label for="upload">Upload Progress:</label>
3<progress id="upload" value="65" max="100">65%</progress>
4
5<!-- Meter gauge -->
6<label for="disk">Disk Usage:</label>
7<meter
8 id="disk"
9 value="0.72"
10 min="0"
11 max="1"
12 low="0.6"
13 high="0.85"
14 optimum="0.3"
15>72%</meter>
16
17<!-- Output for calculations -->
18<form oninput="result.value = parseInt(a.value) + parseInt(b.value)">
19 <input type="range" id="a" value="50" />
20 <input type="range" id="b" value="50" />
21 <output name="result" for="a b">100</output>
22</form>
🔥

pro tip

Always pair every form control with a <label> element using the for attribute. This improves accessibility by allowing screen readers to announce the label, and it makes the label clickable — users can tap the label text to focus the input.

Live preview of a compact form:

preview
Interactive Elements

Interactive elements allow users to show/hide content, open dialogs, and interact with custom controls using native HTML behavior.

ElementPurpose
<details> / <summary>Disclosure widget (expand/collapse)
<dialog>Modal or non-modal dialog
<menu>Semantic menu container (toolbar, popup)

The <details> element creates an expandable disclosure widget. The <summary> provides the visible label:

details.html
HTML
1<details>
2 <summary>What is semantic HTML?</summary>
3 <p>
4 Semantic HTML means using elements that convey meaning
5 about their content. For example, <code><nav&gt;</code>
6 for navigation, <code><article&gt;</code> for main content,
7 and <code><footer&gt;</code> for footer information.
8 </p>
9</details>
10
11<details open>
12 <summary>Why use details?</summary>
13 <ul>
14 <li>No JavaScript required for basic toggle behavior</li>
15 <li>Built-in keyboard accessibility</li>
16 <li>Screen reader friendly</li>
17 <li>Can be styled with CSS</li>
18 </ul>
19</details>

The <dialog> element creates modal or non-modal dialogs. Use the .showModal() method for modals:

dialog.html
HTML
1<!-- Modal dialog -->
2<dialog id="myDialog">
3 <form method="dialog">
4 <h2>Confirm Action</h2>
5 <p>Are you sure you want to delete this item?</p>
6 <menu>
7 <button value="cancel">Cancel</button>
8 <button value="confirm" autofocus>Delete</button>
9 </menu>
10 </form>
11</dialog>
12
13<button id="openDialog">Open Dialog</button>
14
15<script>
16 const dialog = document.getElementById('myDialog');
17 const openBtn = document.getElementById('openDialog');
18
19 openBtn.addEventListener('click', () => {
20 dialog.showModal();
21 });
22
23 dialog.addEventListener('close', () => {
24 console.log('Dialog closed with:', dialog.returnValue);
25 });
26</script>

Live preview of interactive elements:

preview
Tables

HTML tables display tabular data in rows and columns. Use the semantic table elements to structure data, not for layout purposes.

ElementPurpose
<table>Table container
<caption>Table title / description
<thead>Header rows group
<tbody>Body rows group
<tfoot>Footer rows group
<tr>Table row
<th>Header cell (scope attribute for accessibility)
<td>Data cell
<colgroup> / <col>Column-level styling
table.html
HTML
1<table>
2 <caption>
3 Monthly savings report for Q1 2026
4 </caption>
5 <colgroup>
6 <col style="background: #f5f5f5;" />
7 <col />
8 <col style="background: #f5f5f5;" />
9 </colgroup>
10 <thead>
11 <tr>
12 <th scope="col">Month</th>
13 <th scope="col">Income</th>
14 <th scope="col">Expenses</th>
15 <th scope="col">Savings</th>
16 </tr>
17 </thead>
18 <tbody>
19 <tr>
20 <th scope="row">January</th>
21 <td>$5,000</td>
22 <td>$3,200</td>
23 <td>$1,800</td>
24 </tr>
25 <tr>
26 <th scope="row">February</th>
27 <td>$5,200</td>
28 <td>$3,500</td>
29 <td>$1,700</td>
30 </tr>
31 <tr>
32 <th scope="row">March</th>
33 <td>$5,400</td>
34 <td>$3,100</td>
35 <td>$2,300</td>
36 </tr>
37 </tbody>
38 <tfoot>
39 <tr>
40 <th scope="row">Total</th>
41 <td>$15,600</td>
42 <td>$9,800</td>
43 <td>$5,800</td>
44 </tr>
45 </tfoot>
46</table>

best practice

Use scope="col" on column headers and scope="row" on row headers. This is critical for screen readers to associate cells with their headers. Never use tables for page layout — use CSS Grid or Flexbox instead.

Live preview of a styled table:

preview
Scripting

Scripting elements add dynamic behavior, content templates, and fallback content for script-disabled environments.

ElementPurpose
<script>Embeds or references JavaScript code
<noscript>Fallback content for users with JS disabled
<canvas>Drawing surface rendered via JavaScript
<template>Declarative fragment for later use
<slot>Placeholder in Web Components

Use defer or async attributes on scripts to control loading behavior. The <template> element holds HTML that is not rendered until cloned by JavaScript:

scripting.html
HTML
1<!-- External script with defer -->
2<script src="app.js" defer></script>
3
4<!-- Inline script -->
5<script>
6 document.addEventListener('DOMContentLoaded', () => {
7 console.log('Page loaded');
8 });
9</script>
10
11<!-- Module script -->
12<script type="module">
13 import { greet } from './utils.js';
14 greet('World');
15</script>
16
17<!-- Noscript fallback -->
18<noscript>
19 <div class="alert">
20 JavaScript is disabled. Please enable it for full functionality.
21 </div>
22</noscript>
23
24<!-- Template element -->
25<template id="card-template">
26 <article class="card">
27 <img src="" alt="" />
28 <h3></h3>
29 <p></p>
30 </article>
31</template>
32
33<script>
34 const template = document.getElementById('card-template');
35 const clone = template.content.cloneNode(true);
36 clone.querySelector('h3').textContent = 'Dynamic Card';
37 document.body.appendChild(clone);
38</script>

Canvas provides a bitmap drawing surface controlled by JavaScript:

canvas.html
HTML
1<canvas id="myCanvas" width="300" height="200">
2 Your browser does not support the canvas element.
3</canvas>
4
5<script>
6 const canvas = document.getElementById('myCanvas');
7 const ctx = canvas.getContext('2d');
8
9 // Draw a gradient rectangle
10 const gradient = ctx.createLinearGradient(0, 0, 300, 200);
11 gradient.addColorStop(0, '#00FF41');
12 gradient.addColorStop(1, '#00FF41');
13
14 ctx.fillStyle = gradient;
15 ctx.fillRect(10, 10, 280, 180);
16
17 // Draw text
18 ctx.fillStyle = '#000';
19 ctx.font = 'bold 20px system-ui';
20 ctx.textAlign = 'center';
21 ctx.fillText('Canvas Drawing', 150, 110);
22</script>

warning

Place <script> tags just before the closing </body> tag, or use the defer attribute to avoid blocking page rendering. Inline scripts in the <head> will block HTML parsing.
Global Attributes

Global attributes can be used on any HTML element. They provide common configuration, identification, and behavior across all elements.

AttributeDescriptionExample
classSpace-separated list of CSS class namesclass="btn primary"
idUnique identifier for the elementid="header"
styleInline CSS declarationsstyle="color: red;"
titleAdvisory information (tooltip)title="More info"
langLanguage of the element's contentlang="en"
dirText direction (ltr, rtl, auto)dir="rtl"
hiddenElement is not rendered (until="…" variant)hidden
tabindexTab order of focusable elementstabindex="0"
roleARIA role for accessibilityrole="button"
aria-*ARIA states and propertiesaria-label="Close"
data-*Custom data attributesdata-user-id="123"
slotAssigns to a named slot in shadow DOMslot="header"
spellcheckEnable/disable spell checkingspellcheck="false"
contenteditableElement is editable by the usercontenteditable="true"
draggableElement can be draggeddraggable="true"
translateWhether content should be translatedtranslate="no"
autocapitalizeAutomatic capitalization behaviorautocapitalize="words"
inputmodeHints at the type of data inputinputmode="numeric"
isSpecifies a custom element nameis="my-button"
itemscope / itemtypeMicrodata for structured dataitemscope itemtype="…"
global-attributes.html
HTML
1<article
2 class="post featured"
3 id="post-42"
4 lang="en"
5 data-author="jane_doe"
6 data-published="2026-07-07"
7 itemscope
8 itemtype="https://schema.org/Article"
9>
10 <h2
11 contenteditable="true"
12 spellcheck="true"
13 title="Click to edit the title"
14 >
15 Editable Article Title
16 </h2>
17 <p
18 dir="ltr"
19 tabindex="0"
20 role="region"
21 aria-label="Article summary"
22 translate="no"
23 >
24 This section should not be translated.
25 </p>
26 <button
27 aria-label="Delete article"
28 aria-pressed="false"
29 draggable="true"
30 hidden
31 >
32 Delete
33 </button>
34</article>
Void Elements

Void elements (also called self-closing or empty elements) cannot have child content or a closing tag. They represent a single standalone entity in the document.

ElementDescriptionKey Attributes
<area>Clickable area in an image mapshape, coords, href
<base>Base URL for relative URLshref, target
<br>Line break within text
<col>Defines a column within <colgroup>span, style
<embed>Embeds external content or pluginsrc, type, width, height
<hr>Thematic break / horizontal rule
<img>Image embedsrc, alt, width, height
<input>Form input controltype, name, value
<link>External resource link (CSS, favicon)rel, href
<meta>Document metadatacharset, name, content
<source>Media source for <picture>, <video>, <audio>src, type, srcset
<track>Text track for media (subtitles, captions)src, kind, srclang
<wbr>Word break opportunity
void.html
HTML
1<head>
2 <meta charset="UTF-8" />
3 <meta name="viewport" content="width=device-width, initial-scale=1.0" />
4 <base href="https://example.com/" />
5 <link rel="stylesheet" href="styles.css" />
6 <link rel="icon" href="favicon.ico" type="image/x-icon" />
7</head>
8<body>
9 <h1>Welcome</h1>
10 <p>
11 First line.<br />
12 Second line after a break.
13 </p>
14 <hr />
15 <img src="photo.jpg" alt="Photo" width="400" height="300" />
16 <input type="text" name="search" placeholder="Search..." />
17 <picture>
18 <source srcset="image.avif" type="image/avif" />
19 <img src="image.jpg" alt="Fallback" />
20 </picture>
21</body>

info

In HTML5, the trailing slash in void elements is optional (<br> vs <br />). However, including the slash is common practice for XHTML compatibility and consistency. Choose one style and use it consistently.
Custom Elements

Custom Elements allow you to define your own HTML elements with custom behavior. They are part of the Web Components specification and work across all modern browsers.

Custom element names must contain a hyphen (my-element) to differentiate them from built-in elements. You define behavior by extending the HTMLElement class:

custom-element.html
HTML
1<!-- Usage in HTML -->
2<my-counter initial="5" min="0" max="10"></my-counter>
3<my-counter initial="0" min="0" max="100"></my-counter>
4
5<my-tooltip text="Save your work">
6 <button>Save</button>
7</my-tooltip>
8
9<script>
10 // Define a custom element
11 class MyCounter extends HTMLElement {
12 constructor() {
13 super();
14 this._count = parseInt(this.getAttribute('initial') || '0');
15 this._min = parseInt(this.getAttribute('min') || '0');
16 this._max = parseInt(this.getAttribute('max') || '100');
17
18 // Create shadow DOM
19 this.attachShadow({ mode: 'open' });
20 this.shadowRoot.innerHTML = `
21 <style>
22 :host { display: inline-flex; align-items: center; gap: 8px;
23 font-family: system-ui; }
24 button { width: 32px; height: 32px; border-radius: 4px;
25 border: 1px solid #ccc; background: #fff;
26 cursor: pointer; font-size: 18px; }
27 span { min-width: 24px; text-align: center;
28 font-variant-numeric: tabular-nums; }
29 </style>
30 <button id="dec">−</button>
31 <span id="value">${this._count}</span>
32 <button id="inc">+</button>
33 `;
34 }
35
36 connectedCallback() {
37 this.shadowRoot.getElementById('inc')
38 .addEventListener('click', () => this.increment());
39 this.shadowRoot.getElementById('dec')
40 .addEventListener('click', () => this.decrement());
41 }
42
43 increment() {
44 if (this._count < this._max) {
45 this._count++;
46 this.shadowRoot.getElementById('value').textContent = this._count;
47 }
48 }
49
50 decrement() {
51 if (this._count > this._min) {
52 this._count--;
53 this.shadowRoot.getElementById('value').textContent = this._count;
54 }
55 }
56 }
57
58 // Register the custom element
59 customElements.define('my-counter', MyCounter);
60
61 // Custom element extending built-in (only supported in some browsers)
62 class FancyButton extends HTMLButtonElement {
63 constructor() {
64 super();
65 this.style.borderRadius = '8px';
66 this.style.padding = '12px 24px';
67 }
68 }
69 customElements.define('fancy-button', FancyButton, { extends: 'button' });
70</script>

Custom Elements lifecycle callbacks:

lifecycle.js
JavaScript
1class MyElement extends HTMLElement {
2 // Called when element is created
3 constructor() { super(); }
4
5 // Called when element is added to the DOM
6 connectedCallback() { }
7
8 // Called when element is removed from the DOM
9 disconnectedCallback() { }
10
11 // Called when element is moved to a new document
12 adoptedCallback() { }
13
14 // Called when observed attributes change
15 attributeChangedCallback(name, oldVal, newVal) { }
16
17 // Specify which attributes to observe
18 static get observedAttributes() {
19 return ['disabled', 'value'];
20 }
21}
Best Practices

Semantic HTML Checklist

Use semantic elements (<header>, <nav>, <main>, <section>, <article>, <aside>, <footer>) instead of generic <div>s
Include exactly one <main> element per page
Use heading elements (<h1>–<h6>) in a hierarchical order without skipping levels
Use <button> for actions, <a> for navigation — never <div> with onclick
Always provide <label> elements for all form controls
Use <figure> and <figcaption> for self-contained media with captions
Use proper list elements (<ul>, <ol>, <dl>) for lists of items
Use <table> with <thead>, <tbody>, <tfoot> and scope attributes for tabular data
Use <strong> for importance and <em> for emphasis (not <b> and <i>)
Use <time> with datetime attribute for dates and times

Accessibility (A11Y)

All images must have descriptive alt text — decorative images should have alt=""
Use aria-label, aria-labelledby, and aria-describedby where visual labels are insufficient
Ensure all interactive elements are keyboard accessible (Tab, Enter, Space, Escape)
Use proper color contrast — minimum 4.5:1 for normal text, 3:1 for large text
Never remove focus outlines without providing a visible focus indicator
Use landmark elements (&lt;nav&gt;, &lt;main&gt;, &lt;aside&gt;) for screen reader navigation
Provide captions and transcripts for audio and video content
Use role="presentation" or role="none" for purely decorative images
Form validation errors should be announced to screen readers via aria-live regions
Test with keyboard-only navigation before relying on mouse interactions

Performance

Add loading="lazy" to images below the fold to defer loading
Provide width and height attributes on all images to prevent Cumulative Layout Shift (CLS)
Use modern image formats (WebP, AVIF) with fallbacks via &lt;picture&gt;
Use &lt;link rel="preload"&gt; for critical resources and &lt;link rel="preconnect"&gt; for third-party origins
Minimize DOM depth — deeply nested elements increase rendering cost
Use &lt;script defer&gt; or place scripts at the end of &lt;body&gt; to avoid blocking rendering
Use CSS transforms and opacity for animations (they run on the compositor thread)
Avoid using tables for layout — use CSS Grid or Flexbox instead
Use &lt;template&gt; for reusable fragments that are cloned dynamically
Consider using the content-visibility CSS property for lazy rendering of off-screen sections

best practice

Writing semantic HTML is the single most impactful thing you can do for accessibility and SEO. It costs nothing extra in development time and provides enormous benefits. Always choose the most descriptive element for the job.

Example of semantic vs non-semantic markup:

semantic-vs-non-semantic.html
HTML
1<!-- ❌ Non-semantic -->
2<div class="header">
3 <div class="nav">
4 <span onclick="navigate('/')">Home</span>
5 <span onclick="navigate('/about')">About</span>
6 </div>
7</div>
8<div class="content">
9 <div class="section">
10 <div class="title">Welcome</div>
11 <div class="text">Content goes here.</div>
12 </div>
13</div>
14
15<!-- ✅ Semantic -->
16<header>
17 <nav>
18 <a href="/">Home</a>
19 <a href="/about">About</a>
20 </nav>
21</header>
22<main>
23 <section>
24 <h1>Welcome</h1>
25 <p>Content goes here.</p>
26 </section>
27</main>
🔥

pro tip

Bookmark the MDN HTML Elements Reference — it is the definitive source for element documentation, browser compatibility, and usage examples. Keep the HTML spec handy for content model rules and attribute details.
$Blueprint — Engineering Documentation·Section ID: HTML-01·Revision: 1.0