Word and Character Counts for UI Copy, SEO, and Reviews
How to count words and characters the way products and platforms do — limits, diffs, Markdown pitfalls, and a practical editing workflow for developers who ship copy.
A practical guide to semantic HTML — landmarks, headings, lists, and sectioning elements that improve accessibility, SEO, and maintainability without extra frameworks.
By codefunc
HTML is not a styling language. It is a structure language — a way to describe what content is, not how it looks. When you use <nav> instead of <div class="nav">, screen readers announce "navigation landmark." When you use <h2> instead of <span class="title">, search engines understand document hierarchy. Semantic HTML is the foundation of accessible, SEO-friendly, maintainable web pages.
Bottom line: Use HTML elements for their meaning, not their default appearance. <button> for actions, <a> for navigation, <article> for self-contained content. Browser defaults and assistive tech already know what these elements do — you get behavior, accessibility, and SEO for free.
| Benefit | How it works |
|---|---|
| Accessibility | Screen readers announce landmarks, headings, and form controls correctly |
| SEO | Search engines understand content hierarchy and relationships |
| Maintainability | Code describes intent; future developers read structure, not class names |
| Browser features | Reader mode, focus management, and keyboard shortcuts work automatically |
| Resilience | Pages degrade gracefully when CSS or JS fails to load |
A page built with semantic HTML works — even without stylesheets.
Every HTML page needs a clear skeleton:
<!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="Page description for search results.">
</head>
<body>
<header>
<nav aria-label="Main">...</nav>
</header>
<main id="main-content">
<article>
<h1>Page Title</h1>
...
</article>
</main>
<footer>...</footer>
</body>
</html>
| Element | Purpose |
|---|---|
<!DOCTYPE html> |
Triggers standards mode; always first |
<html lang="en"> |
Root element with language declaration |
<head> |
Metadata, title, links, scripts |
<body> |
Visible content |
<title> |
Browser tab, search results, bookmarks |
lang attributeScreen readers switch pronunciation based on lang. Without it, English content may be read with French phonetics if the system default differs.
<html lang="en">
<p>The <span lang="fr">café</span> opens at noon.</p>
</html>
Landmark elements create navigable regions. Screen reader users can jump between them with keyboard shortcuts.
| Element | Landmark role | Use for |
|---|---|---|
<header> |
banner (if top-level) | Site branding, primary nav |
<nav> |
navigation | Navigation links |
<main> |
main | Primary page content (one per page) |
<article> |
article | Self-contained content (blog post, card) |
<section> |
region (if labeled) | Thematic grouping with heading |
<aside> |
complementary | Related but tangential content |
<footer> |
contentinfo (if top-level) | Site footer, legal links |
<main> per page — the primary content region<nav> elements, use aria-label<section> needs a heading — otherwise it has no semantic value<article> is self-contained — could be syndicated and still make sense<nav aria-label="Main">...</nav>
<nav aria-label="Footer">...</nav>
Headings create a hierarchy that screen readers and search engines use to understand content structure.
| Rule | Example |
|---|---|
One <h1> per page |
<h1>JSON Formatter</h1> |
| Don't skip levels | h1 → h2 → h3, not h1 → h4 |
| Nest logically | Subsections use next level down |
| Headings describe content | "FAQ" not "Section 3" |
<h1>CSS Flexbox Guide</h1>
<h2>What is Flexbox?</h2>
<p>Flexbox is a one-dimensional layout method...</p>
<h2>Container Properties</h2>
<h3>flex-direction</h3>
<p>Controls the main axis...</p>
<h3>justify-content</h3>
<p>Distributes items along the main axis...</p>
<h2>Item Properties</h2>
<h3>flex-grow</h3>
<p>Defines how much an item should grow...</p>
| Mistake | Problem | Fix |
|---|---|---|
Using <h2> because it looks smaller |
Breaks hierarchy | Use CSS for sizing |
Multiple <h1> elements |
Confuses document outline | One <h1>, sections get <h2> |
Skipping from <h2> to <h5> |
Screen reader users lose context | Use sequential levels |
| Heading for visual styling only | Pollutes outline | Use <p> with CSS class |
Use lists when content is a collection of related items.
For items where order doesn't matter:
<ul>
<li>JSON Formatter</li>
<li>JWT Decoder</li>
<li>Base64 Encoder</li>
</ul>
For sequences, rankings, or steps:
<ol>
<li>Clone the repository</li>
<li>Install dependencies</li>
<li>Run the dev server</li>
</ol>
For key-value pairs, glossaries, and metadata:
<dl>
<dt>Algorithm</dt>
<dd>HS256 — HMAC with SHA-256</dd>
<dt>Expiration</dt>
<dd>2026-07-08T12:00:00Z</dd>
</dl>
Screen readers announce list length and position ("item 2 of 5"), helping users understand content scope.
Tables are for tabular data — rows and columns with headers. Never use tables for page layout.
<table>
<caption>HTTP Status Codes</caption>
<thead>
<tr>
<th scope="col">Code</th>
<th scope="col">Meaning</th>
<th scope="col">Use Case</th>
</tr>
</thead>
<tbody>
<tr>
<td>200</td>
<td>OK</td>
<td>Successful GET request</td>
</tr>
<tr>
<td>404</td>
<td>Not Found</td>
<td>Resource doesn't exist</td>
</tr>
</tbody>
</table>
| Element/Attribute | Purpose |
|---|---|
<caption> |
Describes the table's purpose |
<th scope="col"> |
Header for a column |
<th scope="row"> |
Header for a row |
<thead>, <tbody>, <tfoot> |
Group rows logically |
Forms are where semantics directly affect usability. Native HTML form elements provide keyboard support, validation, and screen reader announcements automatically.
<!-- Explicit association -->
<label for="email">Email address</label>
<input type="email" id="email" name="email" required>
<!-- Implicit wrapping -->
<label>
Email address
<input type="email" name="email" required>
</label>
Never use placeholder as label — it disappears on input and often fails contrast requirements.
| Type | Benefit |
|---|---|
type="email" |
Mobile keyboard shows @ symbol |
type="tel" |
Numeric keypad on mobile |
type="url" |
Shows .com shortcut |
type="number" |
Spinner controls, numeric input |
type="date" |
Native date picker |
type="search" |
Clear button, search semantics |
| Element | Use for |
|---|---|
<button type="button"> |
Actions that don't submit a form |
<button type="submit"> |
Form submission |
<input type="submit"> |
Form submission (less flexible) |
<a href="..."> |
Navigation to another page/resource |
Never use <div onclick> for buttons — no keyboard support, no focus, no screen reader announcement.
Group related inputs:
<fieldset>
<legend>Shipping Address</legend>
<label for="street">Street</label>
<input type="text" id="street" name="street">
<!-- more fields -->
</fieldset>
| Element | Meaning | Example |
|---|---|---|
<strong> |
Important | <strong>Warning:</strong> This deletes data |
<em> |
Emphasis | You <em>must</em> save before closing |
<code> |
Code | Use <code>npm install</code> |
<kbd> |
Keyboard input | Press <kbd>Ctrl</kbd>+<kbd>S</kbd> |
<abbr> |
Abbreviation | <abbr title="HyperText Markup Language">HTML</abbr> |
<time> |
Date/time | <time datetime="2026-07-07">July 7, 2026</time> |
<mark> |
Highlighted | Search results for <mark>JSON</mark> |
<del> |
Deleted | <del>$50</del> $30 |
<ins> |
Inserted | Version <ins>2.0</ins> |
<time> with machine-readable dates<p>Published <time datetime="2026-07-07T10:00:00Z">July 7, 2026</time></p>
The datetime attribute provides a standardized format for search engines and tools.
<!-- Informative image -->
<img src="chart.png" alt="Bar chart showing 40% increase in traffic after SEO changes">
<!-- Decorative image -->
<img src="divider.svg" alt="">
<!-- Complex image with longer description -->
<figure>
<img src="architecture.png" alt="System architecture diagram">
<figcaption>
The frontend communicates with the API gateway, which routes requests to microservices.
</figcaption>
</figure>
| Image type | Alt text approach |
|---|---|
| Informative | Describe content and purpose |
| Decorative | Empty alt (alt="") |
| Functional (in link/button) | Describe the action |
| Complex (charts, diagrams) | Summary + detailed description |
| Text in image | Transcribe the text |
| Anti-pattern | Problem | Fix |
|---|---|---|
<div class="button" onclick> |
No keyboard, no semantics | Use <button> |
<span class="link"> with JS navigation |
Not a real link | Use <a href> |
<br><br> for spacing |
Presentation in markup | Use CSS margin/padding |
<b> for all bold |
No semantic meaning | Use <strong> for importance |
<i> for icons |
Misuse of italic element | Use <span> with aria-hidden icon |
| Table for layout | Confuses screen readers | Use CSS Grid/Flexbox |
| Empty heading for spacing | Pollutes document outline | Use CSS |
Before shipping, validate your markup:
When debugging messy HTML from CMS exports or third-party widgets, format it first with the HTML Beautifier to see structure clearly. For special characters and entities, use the HTML Entities encoder to ensure correct rendering.
React, Vue, and Svelte compile to HTML. The semantics principles apply:
// React — still semantic HTML
function Article({ title, content }) {
return (
<article>
<h2>{title}</h2>
<p>{content}</p>
</article>
);
}
Frameworks add interactivity; they don't replace HTML semantics. A <button> in JSX is still a <button> in the DOM.
Before shipping a page:
<h1> per page, headings in order<main> wraps primary content<nav> with label if multiple<ul>, <ol>, or <dl> — not styled divs<th> with scope, <caption> if complex<label> for every input<button>, links are <a>alt textlang attribute on <html> and inline foreign textUse these codefunc tools alongside this guide:
Semantic HTML is not extra work — it is less work. Native elements come with keyboard support, focus management, and screen reader announcements. Divs with ARIA and JavaScript recreate what browsers already provide. Start with the right element. Add ARIA only when native HTML cannot express the behavior. Test with keyboard and one screen reader before calling it done.
How to count words and characters the way products and platforms do — limits, diffs, Markdown pitfalls, and a practical editing workflow for developers who ship copy.
When to use XPath vs CSS selectors, how to write stable queries, and a browser-side workflow for testing against real HTML without shipping brittle scrapers.
How to format and inspect XML without breaking namespaces, attributes, or mixed content — plus when to beautify vs minify and how XPath fits the workflow.
Find a developer tool