Uncommon HTML Elements You’ll Actually Use: A Practical Guide
Modern HTML includes a bunch of small but powerful elements that improve semantics, accessibility, and UX without heavy JavaScript. In this guide, we’ll explore lesser‑used tags you can add to your toolkit today. We’ll focus on what they’re for, how to use them accessibly, and common pitfalls. Examples are intentionally minimal so you can copy-paste and adapt.
meter: Visualize a scalar measurement within a known range
The meter element represents a value within a known range (e.g., 0–100). Think battery level, storage used, or a poll result.
- Use meter when you know min/max and optionally thresholds (low, high, optimum).
- Use progress for task completion that goes from 0 to 100% over time.
1<label for="storage">Storage used:</label>2<meter id="storage" value="72" min="0" max="100" low="50" high="85" optimum="30">3 72%4</meter>
Accessibility tips:
- Always provide a text label and fall back text inside the element.
- Consider aria-describedby to add context like “Warning above 85%.”
progress: Indicate ongoing task completion
progress shows a task advancing from 0 to 100% (or indeterminate if value is omitted).
1<label for="dl">Downloading…</label>2<progress id="dl" value="32" max="100">32%</progress>
- Indeterminate state:
<progress max="100"></progress>(no value) lets the browser show a spinner/striped bar. - Pair with live regions for dynamic updates if the value changes via JS:
aria-live="polite"on the label or nearby status.
details + summary: Built‑in disclosure without JS
Use details to hide/show extra content with an accessible toggle provided by summary.
1<details>2 <summary>Shipping & returns</summary>3 <p>Free shipping over $50. Returns accepted within 30 days.</p>4</details>
- Add the open attribute for default-open state:
<details open>. - summary should be concise; the rest can contain any HTML.
- Don’t replace important always-needed content with details; use it for optional expansion.
Accessibility tips:
- The native control is keyboard-accessible and announces state changes. Avoid overriding with custom roles unless necessary.
datalist: Autocomplete for text inputs
Pair input with a datalist to offer suggestions while still allowing free text.
1<label for="city">City</label>2<input id="city" name="city" list="city-list" autocomplete="off" />3<datalist id="city-list">4 <option value="New York"></option>5 <option value="London"></option>6 <option value="Tokyo"></option>7</datalist>
- input type can be text, search, url, tel, etc.
- Suggestions aren’t guaranteed to appear identical across browsers; it’s a progressive enhancement.
- Use for short lists or hints; not a replacement for a full searchable dropdown.
optgroup: Structure long selects
optgroup groups related options inside a select, making long lists more navigable.
1<label for="dept">Department</label> 2<select id="dept" name="department"> 3 <optgroup label="Engineering"> 4 <option>Frontend</option> 5 <option>Backend</option> 6 </optgroup> 7 <optgroup label="Operations"> 8 <option>DevOps</option> 9 <option>Security</option>10 </optgroup>11</select>
- Use label for the group name.
- Avoid deeply nested optgroups (not allowed). Keep it to a single level of grouping.
dialog: Native modal and non‑modal dialogs
The dialog element provides a built-in, accessible dialog. Use showModal() for a modal and show() for non-modal.
1<button id="open">Open dialog</button> 2<dialog id="dlg"> 3 <form method="dialog"> 4 <p>Delete this file?</p> 5 <menu> 6 <button value="cancel">Cancel</button> 7 <button value="confirm">Delete</button> 8 </menu> 9 </form>10</dialog>11 12<script>13 const dlg = document.getElementById('dlg');14 document.getElementById('open').addEventListener('click', () => dlg.showModal());15 dlg.addEventListener('close', () => {16 console.log('Result:', dlg.returnValue);17 });18</script>
- method="dialog" auto-closes on button click and sets returnValue.
- The backdrop is provided for modal dialogs; you can style it with
::backdrop. - Use inert (automatically applied by browsers in modal mode) to keep focus trapped.
Accessibility tips:
- Let the native element manage focus. Avoid custom ARIA role="dialog" unless you need polyfills for older browsers.
template: Ship hidden DOM you can clone later
template holds inert DOM that won’t render until you clone/insert it with JavaScript.
1<template id="row-template"> 2 <tr> 3 <td class="name"></td> 4 <td class="value"></td> 5 </tr> 6</template> 7 8<table id="tbl"><tbody></tbody></table> 9<script>10 const tmpl = document.getElementById('row-template');11 const tbody = document.querySelector('#tbl tbody');12 13 function addRow(name, value) {14 const node = tmpl.content.cloneNode(true);15 node.querySelector('.name').textContent = name;16 node.querySelector('.value').textContent = value;17 tbody.appendChild(node);18 }19 20 addRow('Latency', '42ms');21</script>
- Great for repeating UI with minimal JS. Works well with Shadow DOM and components.
picture + source: Responsive images and art direction
picture lets you swap images based on media queries or formats (e.g., AVIF/WebP fallback to JPEG).
1<picture>2 <source type="image/avif" srcset="hero.avif" />3 <source type="image/webp" srcset="hero.webp" />4 <source media="(max-width: 600px)" srcset="hero-small.jpg" />5 <img src="hero.jpg" alt="A person hiking at sunrise" />6</picture>
- Order source elements from most specific to least; img is the fallback and provides the alt text.
- Combine with sizes and srcset on img for density switching.
time: Mark up dates and times for machines
time expresses a date/time in a machine-readable way while rendering human-friendly text.
1<p>Event starts <time datetime="2025-10-21T09:00:00-04:00">Oct 21, 9am EDT</time>.</p>
- datetime must be ISO 8601. Useful for SEO, reminders, and microdata.
data: Bind a readable label to a machine-readable value
data lets you display a label while associating a value for scripts or parsers.
1<p>Top language: <data value="js">JavaScript</data></p>
- Different from data-* attributes; this is visible content with a value.
output: Live calculation results from forms
output represents the result of a calculation, typically updated via JS or the oninput attribute.
1<form oninput="sum.value = Number(a.value) + Number(b.value)">2 <input id="a" type="number" value="5"> +3 <input id="b" type="number" value="7"> =4 <output name="sum" for="a b">12</output>5</form>
- Use for to associate with input ids for accessibility.
mark: Highlight text as relevant
mark marks content as highlighted, for example search matches.
1<p>Results for “html”: Learn <mark>HTML</mark> semantics the fun way.</p>
- Don’t use mark for visual emphasis alone; use CSS or em/strong for emphasis.
abbr: Expand acronyms for clarity
abbr provides the full expansion on hover and to assistive tech.
1<p><abbr title="Internationalization">i18n</abbr> is hard.</p>
- Always include a title for accessibility unless expansion is already in text.
cite: Source of a work
Use cite to reference the title of a work (book, article, film). Not for people’s names.
1<p>Inspired by <cite>The Design of Everyday Things</cite>.</p>
q vs blockquote: Inline vs block quotations
- q is for short inline quotes; browsers may add quotation marks.
- blockquote is for longer passages and supports cite attribute to link the source.
1<p>He said, <q cite="https://example.com/interview">keep it simple</q>.</p>2<blockquote cite="https://example.com/essay">3 <p>Simplicity is the ultimate sophistication.</p>4</blockquote>
ruby, rt, rp: Annotations for East Asian typography
ruby marks content with pronunciation or annotations; rt is the text for the annotation; rp provides parentheses for browsers without ruby support.
1<ruby>2 漢 <rp>(</rp><rt>hàn</rt><rp>)</rp>3 字 <rp>(</rp><rt>zì</rt><rp>)</rp>4</ruby>
- Essential for Japanese furigana and Chinese pinyin.
bdi and bdo: Handle bidirectional text edge cases
- bdi isolates a span so its direction doesn’t affect or get affected by surrounding text.
- bdo overrides direction explicitly with dir="ltr" or dir="rtl".
1<p>User: <bdi>مثال</bdi> scored 1200 points.</p>2<p><bdo dir="rtl">abc 123</bdo></p>
- Prefer bdi for untrusted user-generated names in mixed LTR/RTL contexts.
wbr: Soft wrap opportunity
wbr suggests a place where the browser may break a long token for wrapping.
1<p>Use long-identifiers-like-this<wbr>-that-won’t<wbr>-wrap properly.</p>
- Great for URLs, long class names, or product SKUs.
kbd, samp, var, code: Semantics for technical text
Give semantics to technical content for better readability and theming.
1<p>Press <kbd>Ctrl</kbd> + <kbd>K</kbd> to search.</p>2<p>Run <code>npm run build</code> and check the <samp>Build succeeded</samp> message.</p>3<p>Area = <var>π</var> × <var>r</var><sup>2</sup></p>
- Use CSS to style these consistently in docs and UIs.
address: Contact details for the nearest ancestor article/section
1<address>3</address>
- Don’t use for arbitrary postal addresses outside of author/contact context.
figure + figcaption: Self-contained media with a caption
1<figure>2 <img src="chart.png" alt="Revenue by quarter">3 <figcaption>Figure 1: Quarterly revenue since 2022.</figcaption>4</figure>
- Lets you move the figure without breaking the caption’s association.
fieldset + legend: Group form controls semantically
1<fieldset>2 <legend>Billing address</legend>3 <!-- fields -->4</fieldset>
- Improves screen reader navigation and comprehension for grouped inputs.
Bonus attributes to know
- hidden: Hide elements from layout and accessibility tree:
<div hidden>…</div> - inert: Make a subtree unfocusable and ignored by AT (supported natively in modern browsers):
<div inert>…</div> - translate: Hint to translation tools which content should be translated.
Common pitfalls and best practices
- Prefer semantic elements over generic div/span; it helps accessibility, SEO, and maintainability.
- Don’t overuse ARIA. Native semantics (e.g., details/summary, dialog) are more robust.
- Provide labels for form-associated elements (meter, progress, output, input+datalist).
- Test keyboard navigation and focus order, especially when using dialog.
- Use ISO 8601 for time datetime and keep time zones explicit when relevant.
Quick reference by use case
- Show a measurement within known bounds: meter
- Indicate task completion: progress
- Hide/show extra content: details + summary
- Light autocomplete suggestions: input + datalist
- Group select options: optgroup
- Modal/non-modal overlays: dialog
- Prebuild markup to clone later: template
- Responsive and art-directed images: picture + source
- Machine-readable dates: time
- Label with machine value: data
- Computed form results: output
- Highlight relevance: mark
- Acronym expansion: abbr
- Book/article titles: cite
- Quotations: q (inline), blockquote (block)
- East Asian annotations: ruby/rt/rp
- Bidirectional isolation/override: bdi/bdo
- Optional word breaks: wbr
- Technical semantics: kbd/samp/var/code
- Contact info: address
- Media with caption: figure + figcaption
- Group form controls: fieldset + legend
Further reading (MDN)
You can dive deeper into each element on MDN Web Docs: https://developer.mozilla.org/en-US/docs/Web/HTML
- MDN:
<meter> - MDN:
<progress> - MDN:
<details>and<summary> - MDN:
<datalist> - MDN:
<optgroup> - MDN:
<dialog> - MDN:
<template> - MDN:
<picture>and<source> - MDN:
<time> - MDN:
<data> - MDN:
<output> - MDN:
<mark> - MDN:
<abbr> - MDN:
<cite> - MDN:
<q>and<blockquote> - MDN:
<ruby>,<rt>,<rp> - MDN:
<bdi>,<bdo> - MDN:
<wbr> - MDN:
<kbd>,<samp>,<var>,<code> - MDN:
<address> - MDN:
<figure>,<figcaption> - MDN:
<fieldset>,<legend>
Add one or two of these to your next UI, and you’ll get better semantics and accessibility essentially for free.