<!doctype html>
Document
Puts the browser in standards mode. It carries no version information — that is its only job.
html Copy < !doctype html >
< html lang ="en" >
Watch out Without it you get quirks mode, where old layout bugs are emulated on purpose.
<html>
Document
The root element. Carries the page language and, for right-to-left scripts, the direction.
html Copy < html lang ="en" dir ="ltr" >
Watch out lang is not optional: it sets screen-reader pronunciation, hyphenation and translation.
<head>
Document
Information about the document: title, metadata, stylesheets, scripts. None of it is drawn.
<body>
Document
The document itself — everything a reader sees.
<meta charset>
Document
Declares the character encoding. Always UTF-8.
html Copy < meta charset ="utf-8" >
Watch out Must appear within the first 1024 bytes, so it goes first in the head.
<meta name="viewport">
Document
Tells a phone to render at device width instead of 980px and scaling down.
html Copy < meta name ="viewport" content ="width=device-width, initial-scale=1" >
Watch out Never add user-scalable=no — it blocks zoom, which people need.
<title>
Document
The tab, the bookmark, the search result and the first thing a screen reader announces.
Watch out Put the distinctive part first: "Learn HTML — DOMVYBE", not the other way round.
<link>
Document
A relationship to an external resource: a stylesheet, an icon, a canonical URL, a preload.
html Copy < link rel ="stylesheet" href ="/style.css" >
< link rel ="icon" href ="/favicon.svg" type ="image/svg+xml" >
< link rel ="canonical" href ="https://example.com/page/" >
< link rel ="preload" as ="font" type ="font/woff2" crossorigin href ="/f.woff2" >
<script>
Document
Loads or contains JavaScript.
html Copy < script type ="module" src ="/app.js" > </ script > <!-- deferred, module scope -->
< script defer src ="/old.js" > </ script > <!-- after parsing, in order -->
< script async src ="/analytics.js" > </ script > <!-- whenever it lands -->
Watch out defer and async are ignored on inline scripts — those always run immediately.
<style>
Document
CSS inside the document. Useful for the handful of rules needed before the stylesheet arrives.
<base>
Document
Sets the base URL every relative link resolves against. One per document, and it affects everything after it.
Watch out Rarely worth it — it surprises the next person to read the page.
<meta name="description">
Document
The sentence a search engine may show under your title. 50–160 characters, unique per page.
html Copy < meta name ="description" content ="Solid oak doors, painted in any colour, with a frame measured on site." >
Watch out It is not a ranking signal, but it decides whether anyone clicks. A duplicate description across a site is worse than none.
<link rel="canonical">
Document
The address this page should be indexed under, when the same content is reachable at several URLs.
html Copy < link rel ="canonical" href ="https://example.com/doors/painted-oak" >
Watch out Absolute URL. Filters and tracking parameters are the usual reason two URLs hold one page.
Open Graph tags
Document
What a link looks like when it is pasted into a chat or a post.
html Copy < meta property ="og:title" content ="Painted oak door" >
< meta property ="og:description" content ="Five days, made to order." >
< meta property ="og:image" content ="https://example.com/og/painted.png" >
< meta property ="og:type" content ="product" >
< meta name ="twitter:card" content ="summary_large_image" >
Watch out 1200×630 renders well everywhere. A relative image URL is dropped — make it absolute.
<meta name="theme-color">
Document
Tints the browser interface around the page on mobile and in installed apps.
html Copy < meta name ="theme-color" content ="#07090c" >
< meta name ="theme-color" content ="#fff" media ="(prefers-color-scheme: light)" >
<script> defer and async
Document
How a classic script is fetched and when it runs.
html Copy < script src ="a.js" > </ script > <!-- blocks parsing -->
< script src ="a.js" defer > </ script > <!-- fetches now, runs after parsing, in order -->
< script src ="a.js" async > </ script > <!-- fetches now, runs whenever it lands -->
< script type ="module" src ="a.js" > </ script > <!-- deferred by default -->
Watch out defer for anything that touches the DOM; async only for something wholly independent, like analytics.
<link rel="preload">
Document
Start fetching something the page will certainly need, before the parser reaches it.
html Copy < link rel ="preload" href ="/fonts/space.woff2" as ="font" type ="font/woff2" crossorigin >
< link rel ="preconnect" href ="https://cdn.example.com" >
Watch out Preload everything and you have prioritised nothing. One or two per page, and only what is on the critical path.
<noscript>
Document
Content shown only when scripting is off or has failed.
Watch out Useful as a fallback message, and as a reminder that a page which renders nothing without JavaScript has a cost.
<h1> … <h6>
Text
Headings. They are the document outline, not sizes — screen readers list them so a page can be skimmed.
Watch out One h1 per page. Do not skip levels to get a smaller size; that is what CSS is for.
<p>
Text
A paragraph. Accepts phrasing content only.
Watch out Put a div or a heading inside one and the browser closes the paragraph before it.
<strong>
Text
Strong importance, seriousness or urgency. Bold by default — but the meaning is the point.
<em>
Text
Stress emphasis: the sentence changes meaning depending on which word carries it.
<b>
Text
Bold with no added importance — a keyword, a product name, a lead-in.
<i>
Text
A different voice or mood: a technical term, a taxonomic name, a thought.
<mark>
Text
Highlighted because it is relevant to what the reader is doing right now — a search hit, for instance.
<small>
Text
Side comments and small print: legal text, attribution, caveats.
<s> / <del> / <ins>
Text
s is no longer accurate. del is removed content, ins is added content — both take datetime and cite.
<blockquote>
Text
A quoted block. Takes cite with the source URL.
html Copy < figure >
< blockquote cite ="https://example.com" >
< p > Programs must be written for people to read.</ p >
</ blockquote >
< figcaption > Abelson and Sussman, < cite > SICP</ cite > </ figcaption >
</ figure >
<q>
Text
An inline quotation. The browser adds the quotation marks, in the right style for the language.
<cite>
Text
The title of a work — a book, a film, a paper. Not the name of the person.
<code>
Text
A fragment of code. Inside a pre for a block.
Watch out A < inside must be written < or the browser reads it as a tag.
<pre>
Text
Preformatted: whitespace and newlines are preserved exactly.
<kbd> / <samp> / <var>
Text
A key to press, output from a program, and a variable name.
<abbr>
Text
An abbreviation. The title attribute carries the expansion.
html Copy < abbr title ="Cascading Style Sheets" > CSS</ abbr >
<time>
Text
A date or time a machine can read, with any wording you like for people.
html Copy < time datetime ="2026-09-21" > 21 September 2026</ time >
<br>
Text
A line break that is part of the content — an address, a line of verse.
Watch out Not for spacing between paragraphs. That is a margin.
<hr>
Text
A thematic break: the subject changes. Not a decorative line — use a border for that.
<span>
Text
An inline container with no meaning. For styling or scripting a run of text.
<bdi>
Text
Isolates a fragment whose direction is unknown — a user name — so it cannot disturb the line around it.
Character entities
Text
Four characters must be escaped in HTML.
html Copy < < less than
> ; > greater than
& & ampersand
" " inside a double-quoted attribute
a space that does not break
<sub> / <sup>
Text
Subscript and superscript — chemistry, footnote markers, ordinals.
html Copy H< sub > 2</ sub > O · 4< sup > th</ sup > · < a href ="#fn1" > < sup > 1</ sup > </ a >
Watch out For mathematics, MathML or an image with a description is better than nested sup tags.
<data>
Text
Text for a person, with a machine-readable value beside it.
html Copy < data value ="480" > £480</ data >
< data value ="8901234" > Product no. 8901234</ data >
Watch out The datetime twin of this is <time>.
<address>
Text
Contact details for the nearest article or for the page as a whole.
Watch out Not for postal addresses in general — only for how to reach the author or owner.
<dfn>
Text
Marks the place where a term is defined, rather than every use of it.
<wbr>
Text
A place a long word may break, if it has to.
html Copy https://example.com/a/< wbr > very/< wbr > long/< wbr > path
<u> and <bdo>
Text
<u> is a non-textual annotation, like a spelling error. <bdo> forces text direction.
Watch out Underlining anything that is not a link is a usability problem; that is why <u> is rare.
<a>
Links & media
A link. The text inside is what a screen reader announces, so it must make sense on its own.
html Copy < a href ="/learn/" > Another page here</ a >
< a href ="https://example.com" target ="_blank" rel ="noopener" > Another site</ a >
< a href ="#forms" > Further down this page</ a >
< a href ="mailto:a@b.com" > Start an email</ a >
< a href ="/file.zip" download > Save the file</ a >
Watch out target="_blank" always needs rel="noopener". Never write "click here".
<img>
Links & media
An image. alt is what the image says, not what it looks like.
html Copy < img src ="/a.jpg" alt ="A brass lever on a walnut door" width ="1600" height ="900" loading ="lazy" >
Watch out alt="" for decoration — empty, not missing. width and height reserve the space and stop the page jumping.
srcset / sizes
Links & media
Offers the browser several sizes of the same image so it can pick before layout.
html Copy < img src ="/h-800.jpg"
srcset ="/h-400.jpg 400w, /h-800.jpg 800w, /h-1600.jpg 1600w"
sizes ="(max-width: 700px) 100vw, 50vw"
alt ="…" width ="1600" height ="900" >
Watch out sizes must describe the CSS width the image is drawn at. A wrong one is worse than none.
<picture>
Links & media
Chooses between genuinely different files: another format, or a different crop.
html Copy < picture >
< source srcset ="/h.avif" type ="image/avif" >
< source media ="(max-width: 700px)" srcset ="/h-square.jpg" >
< img src ="/h.jpg" alt ="…" width ="1600" height ="900" >
</ picture >
Watch out The img is the fallback and the element that is styled. alt always lives on it.
<figure> / <figcaption>
Links & media
Self-contained content with a visible caption.
Watch out The caption and the alt do different jobs and should not be the same sentence.
<video>
Links & media
Video, with the browser player if you add controls.
html Copy < video src ="/v.mp4" poster ="/p.jpg" width ="1600" height ="900"
controls playsinline preload ="metadata" >
< track kind ="captions" src ="/v.en.vtt" srclang ="en" label ="English" default >
</ video >
Watch out Autoplay only works muted. Always include playsinline or iOS takes over the screen.
<audio>
Links & media
Audio. With controls it is a complete player; give it a caption saying what it is.
<track>
Links & media
A WebVTT captions, subtitles, descriptions or chapters file for a video.
Watch out A cross-origin VTT needs CORS headers, and file:// will not load one at all.
<iframe>
Links & media
Another complete document inside a rectangle, with its own origin.
html Copy < iframe src ="…" title ="…" loading ="lazy" sandbox ="allow-scripts" > </ iframe >
Watch out title is the accessible name. allow-scripts together with allow-same-origin removes the sandbox entirely.
<svg>
Links & media
Vector graphics inline in the page, where CSS can reach them.
Watch out Decorative icon inside a labelled button: aria-hidden="true". Standalone meaning: role="img" and a <title> first.
<canvas>
Links & media
A bitmap you draw on with JavaScript. Nothing drawn is in the DOM, so it needs a text alternative.
target="_blank"
Links & media
Opens in a new tab. Modern browsers imply rel="noopener", but state it anyway.
html Copy < a href ="https://example.com" target ="_blank" rel ="noopener noreferrer" >
Their site < span aria-hidden ="true" > ↗</ span >
< span class ="sr-only" > (opens in a new tab)</ span >
</ a >
Watch out Say that it opens a new tab. A screen-reader user otherwise finds the back button dead.
download
Links & media
Saves the target instead of navigating to it, optionally under a new name.
html Copy < a href ="/exports/doors.csv" download ="doors-2026.csv" > Download the list</ a >
Watch out Only honoured for same-origin URLs and blob: URLs.
mailto: and tel:
Links & media
Links that open a mail client or start a call.
html Copy < a href ="mailto:hello@example.com?subject=Doors" > hello@example.com</ a >
< a href ="tel:+994501234567" > +994 50 123 45 67</ a >
Watch out Write the number in the link text the way a person reads it, and in the href the way a phone dials it.
<iframe> sandbox
Links & media
Drops privileges for the framed document and grants them back one at a time.
html Copy < iframe src ="/preview" sandbox ="allow-scripts" title ="Preview" > </ iframe >
<!-- allow-scripts allow-same-origin together is the same as no sandbox -->
Watch out Without allow-same-origin the frame gets an opaque origin: no storage, no cookies, and the parent cannot read it. That is the point.
<iframe> loading and allow
Links & media
Lazy-load an embed, and state which capabilities it may use.
html Copy < iframe src ="https://player.example/v/1" title ="The film"
loading ="lazy" allow ="fullscreen; picture-in-picture"
width ="560" height ="315" > </ iframe >
Watch out A title is required for a frame — it is what a screen reader announces.
<source>
Links & media
One candidate inside <picture>, <video> or <audio>. The first that matches wins.
html Copy < picture >
< source srcset ="/door.avif" type ="image/avif" >
< source srcset ="/door.webp" type ="image/webp" >
< img src ="/door.jpg" alt ="A painted oak door" width ="1200" height ="800" >
</ picture >
Watch out The <img> is not a fallback afterthought: it is the element that actually renders, and it carries the alt.
Inline <svg> vs <img src=".svg">
Links & media
Inline SVG can be styled by the page and read by CSS; an SVG in an <img> cannot.
html Copy < svg viewBox ="0 0 24 24" width ="20" height ="20" aria-hidden ="true" fill ="none" stroke ="currentColor" >
< path d ="M5 12h14" />
</ svg >
Watch out currentColor is the reason icons are inlined: they follow the text colour for free.
<ul>
Lists & tables
An unordered list — the order does not matter. Only li may be a direct child.
<ol>
Lists & tables
An ordered list — the order is the content. Takes start, reversed and type.
html Copy < ol start ="4" reversed type ="a" >
<li>
Lists & tables
A list item. A nested list goes inside the li it belongs to, never between two.
<dl> / <dt> / <dd>
Lists & tables
Name and value pairs: a glossary, a specification sheet, metadata.
html Copy < dl >
< div > < dt > Material</ dt > < dd > Aluminium</ dd > </ div >
< div > < dt > Tolerance</ dt > < dd > 1 mm</ dd > </ div >
</ dl >
Watch out Wrapping each pair in a div is allowed and makes it far easier to lay out.
<table>
Lists & tables
Data with two dimensions. Not a layout tool.
html Copy < table >
< caption > Lead times</ caption >
< thead > < tr > < th scope ="col" > Finish</ th > < th scope ="col" > Days</ th > </ tr > </ thead >
< tbody > < tr > < th scope ="row" > Painted</ th > < td > 5</ td > </ tr > </ tbody >
</ table >
<caption>
Lists & tables
The table's name and accessible name. Must be the first child of the table.
<th> scope
Lists & tables
A header cell. scope="col" or "row" tells assistive technology which cells it describes.
Watch out Without scope, a cell is announced as a bare value with no idea which row or column it belongs to.
colspan / rowspan
Lists & tables
How many columns or rows a cell covers. Every row must still add up to the same total.
<ol start> and reversed
Lists & tables
Begin the numbering somewhere else, or count down.
html Copy < ol start ="4" > …</ ol >
< ol reversed > …</ ol >
< li value ="9" > …</ li >
<colgroup> / <col>
Lists & tables
Styles or spans whole columns without touching every cell.
html Copy < table >
< colgroup > < col > < col style ="width: 30%" > </ colgroup >
…
</ table >
<thead> / <tbody> / <tfoot>
Lists & tables
Row groups. A header group can repeat when a long table is printed.
Watch out tfoot goes after tbody in the markup; browsers render it at the bottom regardless.
<form>
Forms
Collects named values and sends them somewhere.
html Copy < form action ="/subscribe" method ="post" >
Watch out method="get" puts values in the query string; "post" puts them in the body. Only named controls are sent.
<label>
Forms
Names a control. Either for="id" or wrap the input.
Watch out A placeholder is not a label: it disappears the moment someone types.
<input>
Forms
The type changes the control, the phone keyboard, the validation and what is announced.
html Copy text email tel url number range date time
password search checkbox radio file color hidden
Watch out type="number" is for quantities. A postcode, PIN or card number is text with inputmode="numeric".
<textarea>
Forms
Multi-line text. The value is the content between the tags, not a value attribute.
<select> / <option>
Forms
A choice from a fixed list. optgroup groups options; multiple allows several.
Watch out The closed control is stylable; the open dropdown list is drawn by the operating system and is not.
<button>
Forms
A button. Inside a form the default type is submit.
Watch out If it is not meant to submit, you must write type="button". This causes more surprise reloads than anything else.
<fieldset> / <legend>
Forms
Groups related controls and names the group. Essential for a set of radio buttons.
<datalist>
Forms
Suggestions for an input. Unlike select, the reader may type something else.
required / pattern / min / max
Forms
Constraints the browser enforces before submitting, and announces in the reader's own language.
html Copy < input required minlength ="8" maxlength ="40" >
< input type ="number" min ="1" max ="40" step ="1" >
< input pattern ="[0-9]{4}" title ="Four digits" >
Watch out pattern is anchored at both ends automatically. Always pair it with title. And validate again on the server.
autocomplete
Forms
Names what a field holds so the browser and password manager can fill it in one tap.
html Copy name given-name family-name email tel organization
street-address address-level2 postal-code country-name
cc-number cc-exp username current-password new-password one-time-code
Watch out Do not switch it off on address or password fields — it makes the form harder for everyone.
readonly vs disabled
Forms
readonly is focusable and IS submitted. disabled is not focusable and is NOT submitted.
Watch out If the value must arrive but not be edited, readonly is the one you want.
Text-like input types
Forms
text, email, tel, url, search, password — the keyboard and the validation change with the type.
html Copy < input type ="email" autocomplete ="email" required >
< input type ="tel" inputmode ="tel" autocomplete ="tel" >
< input type ="url" placeholder ="https://" >
< input type ="search" >
Watch out type="number" is for quantities, never for phone numbers, card numbers or postcodes: it strips leading zeros and spins on scroll.
Date and time inputs
Forms
date, time, datetime-local, month and week, with a native picker.
html Copy < input type ="date" min ="2026-01-01" max ="2026-12-31" value ="2026-09-21" >
Watch out The value is always ISO — "2026-09-21" — whatever the picker shows the user.
<input type="file">
Forms
Choose one or more files. Read them from the files property, never from value.
html Copy < input type ="file" accept ="image/png, image/jpeg" multiple >
< input type ="file" accept ="image/*" capture ="environment" >
Watch out accept is a filter in the picker, not a guarantee. Check the type on the server.
<input type="range">
Forms
A slider. Always pair it with a visible number: a slider alone hides the value.
html Copy < label for ="days" > Lead time</ label >
< input id ="days" type ="range" min ="1" max ="30" step ="1" value ="5"
oninput ="out.value = this.value" >
< output id ="out" > 5</ output >
<input type="checkbox"> and radio
Forms
Checkboxes are independent; radios sharing a name are one choice.
html Copy < fieldset >
< legend > Finish</ legend >
< label > < input type ="radio" name ="finish" value ="painted" checked > Painted</ label >
< label > < input type ="radio" name ="finish" value ="oiled" > Oiled</ label >
</ fieldset >
Watch out Radios without a shared name are not a group. Radios without a fieldset and legend have no group label.
<input type="hidden">
Forms
Sends a value the user does not edit — an id, a token, a return path.
Watch out Hidden from the page, not from the user. Anything here can be changed before it is sent.
<optgroup>
Forms
Groups options under a label inside a select.
html Copy < select >
< optgroup label ="Oak" >
< option value ="painted" > Painted</ option >
< option value ="oiled" > Oiled</ option >
</ optgroup >
</ select >
novalidate and formnovalidate
Forms
Turns off the browser’s own error bubbles — for the form, or for one button.
html Copy < form novalidate > …</ form >
< button formnovalidate > Save a draft</ button >
Watch out Keep required and type even when you validate yourself: assistive technology reads them.
formaction and formmethod
Forms
Lets one button submit the same form somewhere else.
html Copy < button type ="submit" > Save</ button >
< button type ="submit" formaction ="/drafts" > Save as a draft</ button >
inputmode and enterkeyhint
Forms
Chooses the on-screen keyboard and what its action key says, without changing the input type.
html Copy < input inputmode ="numeric" pattern ="[0-9]*" enterkeyhint ="done" >
< input type ="search" enterkeyhint ="search" >
The form attribute
Forms
Associates a control with a form it is not inside.
html Copy < form id ="order" > …</ form >
< button type ="submit" form ="order" > Order</ button >
<nav>
Sections
A major block of navigation links. Not every group of links.
Watch out With more than one, give each an aria-label so they can be told apart.
<main>
Sections
The unique content of this page. Exactly one, and not inside header, nav, article, aside or footer.
<article>
Sections
Something that would still make sense on its own: a post, a card, a comment.
<section>
Sections
A thematic grouping — and it should have a heading.
Watch out A section with no heading is worse than a div: it announces a region and then fails to say what it is.
<aside>
Sections
Related but separable: a sidebar, a pull quote, related links.
<div>
Sections
A container with no meaning. Correct and honest when the grouping exists for layout.
<search>
Sections
The landmark for a search or filter region — the element that replaces role="search".
html Copy < search >
< form action ="/doors" >
< label for ="q" > Search doors</ label >
< input id ="q" type ="search" name ="q" >
</ form >
</ search >
<hgroup>
Sections
A heading with its subtitle, so the subtitle is not a second heading in the outline.
html Copy < hgroup >
< h1 > Painted oak door</ h1 >
< p > Made to order in five days</ p >
</ hgroup >
Heading order
Sections
One h1 per page, then h2, h3 — with nothing skipped. It is how a screen reader user navigates.
Watch out Heading levels are structure, not size. Style them with CSS; do not pick h4 because it looks right.
Landmarks
Sections
header, nav, main, aside and footer map to landmarks that can be jumped between.
Watch out One main per page. Two navs need distinct aria-labels, or they are announced identically.
<details> / <summary>
Interactive
A disclosure widget with keyboard support and no JavaScript.
html Copy < details name ="faq" >
< summary > What is included?</ summary >
< p > Frame, leaf and fitting.</ p >
</ details >
Watch out summary must be the first child. A shared name attribute makes a group behave like an accordion.
<dialog>
Interactive
A real modal: inert background, trapped focus, Escape to close, rendered in the top layer.
js Copy dialog.showModal (); // modal
dialog.show (); // non-modal
dialog.close ("ok" );
dialog.returnValue;
Watch out A form with method="dialog" inside closes it and puts the button value in returnValue.
popover
Interactive
A light overlay that closes on Escape or a click outside, with no script.
html Copy < button popovertarget ="menu" > Options</ button >
< div id ="menu" popover > …</ div >
<progress> / <meter>
Interactive
progress is a task moving to completion. meter is a reading on a known scale, coloured by low/high/optimum.
<output>
Interactive
The result of a calculation. It is a live region by default, so changes are announced.
<template>
Interactive
Markup that is parsed but inert: not rendered, images not loaded, scripts not run. Clone it to use it.
js Copy const node = tpl.content.cloneNode (true );
node.querySelector (".title" ).textContent = d.title;
list.append (node);
<slot>
Interactive
A hole in a shadow tree where the element's own children appear.
<details name>
Interactive
Give several details the same name and only one can be open — an accordion with no JavaScript.
html Copy < details name ="faq" > < summary > One</ summary > …</ details >
< details name ="faq" > < summary > Two</ summary > …</ details >
popovertarget
Interactive
Wires a button to a popover without a line of script, with light dismiss and the top layer included.
html Copy < button popovertarget ="menu" > Options</ button >
< div id ="menu" popover > …</ div >
<dialog> modal or not
Interactive
showModal() traps focus, adds a backdrop and blocks the page. show() does none of that.
js Copy dialog.showModal ();
dialog.close ("saved" );
dialog.addEventListener ("close" , () => console.log (dialog.returnValue));
Watch out A form with method="dialog" inside closes it on submit and sets returnValue.
id
Attributes
A unique address for one element: a label's for, an anchor target, aria-labelledby.
Watch out Two elements with the same id is not an error the browser reports — it quietly uses the first.
class
Attributes
One or more names, space separated. The main hook for CSS.
data-*
Attributes
Your own data. Read from element.dataset with the name in camelCase.
js Copy <button data-panel="specs" data-open-delay="200" >
el.dataset.panel; // "specs"
el.dataset.openDelay; // "200" — always a string
hidden
Attributes
Removes the element from the page and from assistive technology. Equivalent to display: none.
inert
Attributes
The element and everything inside it stop responding to clicks and focus. What showModal() applies to the page.
tabindex
Attributes
0 puts a non-interactive element in the tab order; -1 makes it focusable by script only.
Watch out Never use a positive value. It reorders the whole page's tab sequence.
aria-label / aria-labelledby
Attributes
Gives an element an accessible name when its content does not — an icon-only button, for instance.
Watch out Prefer real text. A name that differs from the visible label breaks voice control.
aria-expanded / aria-controls
Attributes
States whether a disclosure is open, and which element it controls.
html Copy < button aria-expanded ="false" aria-controls ="panel" > Details</ button >
aria-live / role="status"
Attributes
Announces content that appeared without a page load. polite waits for a pause; assertive interrupts.
aria-hidden
Attributes
Hides an element from assistive technology while leaving it visible.
Watch out Never on anything focusable — a keyboard user would land on something that does not exist to them.
loading / decoding / fetchpriority
Attributes
loading="lazy" defers off-screen images. decoding="async" keeps decoding off the main thread. fetchpriority="high" for the one image that matters most.
Watch out Never lazy-load the image at the top of the page.
rel values
Attributes
noopener, noreferrer, nofollow, sponsored, ugc, canonical, alternate, preload, preconnect.
contenteditable
Attributes
Makes the content editable in place. Powerful and full of edge cases — reach for a real input first.
translate
Attributes
translate="no" stops automatic translation mangling a product name or a code sample.
lang and dir
Attributes
The language of the content and the direction it runs. Set both on <html>, and again on any passage that differs.
html Copy < html lang ="en" >
< p lang ="az" > Qapı</ p >
< p dir ="rtl" lang ="ar" > …</ p >
Watch out lang decides the voice a screen reader uses, how text is hyphenated, and which quotation marks CSS inserts.
title
Attributes
A tooltip on hover. Invisible on touch, unreliable with a keyboard, and not a substitute for a label.
Watch out The one genuinely good use is on an <iframe> and on <abbr>.
aria-describedby
Attributes
Points at the element that explains a control — a hint, or an error message.
html Copy < input id ="email" aria-describedby ="email-hint" aria-invalid ="true" >
< small id ="email-hint" role ="alert" > That address looks wrong.</ small >
aria-current
Attributes
Marks the one item in a set that is current: page, step, date or location.
html Copy < a href ="/doors" aria-current ="page" > Doors</ a >
aria-pressed and aria-checked
Attributes
State for a toggle button or a custom checkbox.
Watch out If a native <button> or <input type="checkbox"> will do, use it — it carries this for free.
spellcheck, autocapitalize, autocorrect
Attributes
Control the typing conveniences a phone applies.
html Copy < input name ="code" spellcheck ="false" autocapitalize ="off" autocomplete ="off" >
Watch out Turn them off for codes, identifiers and passwords. Leave them on for prose.
draggable
Attributes
Marks an element as a drag source for the HTML drag-and-drop API.
Watch out Drag and drop is keyboard-hostile by default. Give the same action a button as well.
Nothing matches. Try a shorter word.