10 Underrated HTML Tags That Will Replace Your Bloated JS Libraries
Live Demo: View the Interactive Docs
As web developers, we love custom JavaScript packages. We install third-party libraries for autocomplete dropdowns, modal managers, disclosure accordions, and custom progress indicators.
But every line of JavaScript we ship is code the browser has to download, parse, and execute. It increases page weight and introduces potential accessibility bugs.
Did you know that native HTML has built-in features that can replace a surprising amount of custom JS and CSS? In this post, we'll explore 10 underrated, highly semantic HTML elements that will help you write faster, cleaner, and more accessible code out of the box.
1. <datalist> (Native Autocomplete)
The Problem
Building a custom autocomplete dropdown usually requires a heavy select component library or complex JS event listeners to filter arrays and toggle menu visibility on keypress.
Why it matters
The <datalist> element acts as a native autocomplete menu linked to a standard <input> field.
- Native Autocomplete: It filters values automatically based on user typing.
-
Custom entries allowed: Unlike a
<select>drop-down, users can select an option or type their own custom text. -
Form Integration: Works seamlessly inside any standard
<form>.
Code Example
<label for="city-choice">Choose a city:</label>
<input id="city-choice" list="cities" placeholder="Start typing a city..." />
<datalist id="cities">
<option value="Bhubaneswar" />
<option value="Brahmapur" />
<option value="Cuttack" />
<option value="Puri" />
<option value="Sambalpur" />
</datalist>
2. <dialog> (Native Modals & Focus Trapping)
The Problem
Creating accessible modal overlays from scratch is notoriously difficult. You have to write custom JavaScript to handle background scroll blocking, trap the keyboard focus inside the modal (so users don't tab out into the background), and listen for the Escape key to close it.
Why it matters
The <dialog> tag represents a native overlay box that solves these challenges natively:
-
Automatic Focus Management: Tabbing is naturally restricted to the modal elements when opened with
showModal(). -
Keyboard support: Pressing
Escapecloses the modal natively without a single line of JS. -
Semantic backdrop: Style the background dimming using the
::backdropCSS pseudo-element. -
Clean API: Controlled using native methods:
.show(),.showModal(), and.close().
Code Example
<button commandfor="contact-modal" command="show-modal">Open Modal</button>
<dialog id="contact-modal">
<h2>Contact Form</h2>
<form method="dialog">
<label for="name">Name</label><br>
<input type="text" id="name" required><br><br>
<label for="email">Email</label><br>
<input type="email" id="email" required><br><br>
<button type="submit">Submit</button>
<button type="button" commandfor="contact-modal" command="close">Close</button>
</form>
</dialog>
3. <details> + <summary> (No-JS Accordions)
The Problem
For collapsible cards, FAQs, or disclosures, developers often write JavaScript toggle functions, toggling classes like .is-open or .hidden.
Why it matters
The <details> and <summary> tags create a disclosure widget out-of-the-box:
-
Zero JS Accordions: Clicking the
<summary>automatically expands the nested contents. -
CSS hooks: The browser appends the
openattribute natively. You can style the open state using the CSSdetails[open]selector. - SEO & Search Friendly: Text inside closed details tags is still indexed by search engine crawlers and is natively searchable using Ctrl+F.
Code Example
<details>
<summary>What is HTML?</summary>
<p>HTML (HyperText Markup Language) is the standard markup language used to structure pages on the web.</p>
</details>
4. <progress> (Semantic Status Indicators)
The Problem
Creating progress bars usually involves nested <div> tags, a custom width style in CSS, and ARIA roles added manually for screen reader compatibility.
Why it matters
The <progress> element semantically represents the completion progress of a task:
-
Accessibility built-in: Screen readers inherently announce the value and max bounds without manually setting
role="progressbar". -
Indeterminate states: If you omit the
valueattribute, it natively renders a bouncing animation indicating a pending state (perfect for page loading spinners).
Code Example
<h2>File Upload</h2>
<progress value="75" max="100"></progress>
5. <meter> (Scalar Range Gauges)
The Problem
Often, developers use <progress> or custom bars to display scalar values (e.g., password strength, disk usage, or ratings). This is semantically incorrect because a progress bar is meant to track completion, not a fixed measurement.
Why it matters
The <meter> tag is specifically designed for scalar measurements within a known range:
-
Intelligent thresholds: Supports advanced attributes:
min,max,low,high, andoptimum. - Auto-coloring: Browsers natively change the gauge color (e.g. Green for optimum, Yellow/Red for low/high) depending on the value and thresholds.
Code Example
<h2>Password Strength</h2>
<meter min="0" max="100" low="35" high="70" optimum="85" value="80">Strong</meter>
6. <output> (Semantic Form Resulting)
The Problem
Form calculation results (like a shopping cart total) are usually outputted inside generic <span> or <div> tags, making it hard for screen readers to notice when the numbers update dynamically.
Why it matters
The <output> element represents the outcome of a user calculation:
-
Implicit ARIA live-region: Many screen readers treat the tag as a live region (
aria-live="polite"), automatically reading the new calculation aloud to users when it changes. -
Logical link: You can link it to the input fields that generated the value using the
forattribute.
Code Example
<form oninput="result.value=Number(a.value)+Number(b.value)">
<input type="number" id="a" value="10">
+
<input type="number" id="b" value="20">
=
<output name="result" for="a b">30</output>
</form>
7. <mark> (Contextual Highlighting)
The Problem
Highlighting search query matches in text usually involves wrapping strings in a <span class="highlight"> styled with a yellow background.
Why it matters
The <mark> tag indicates text highlighted for reference or relevance:
- Semantic meaning: Communicates relevance to search engine crawlers and accessibility utilities, not just visual styling.
- Default Styles: Instantly applies a readable yellow background that is compatible with user dark mode preferences.
Code Example
<p>Modern developers should learn how to write <mark>semantic HTML</mark> first.</p>
8. <kbd> (Keyboard Input Formatting)
The Problem
When writing technical documentation or tutorials, formatting keyboard shortcuts can look inconsistent if we only rely on generic inline code tags.
Why it matters
The <kbd> tag represents user keyboard input:
-
Nesting support: Nesting tags (like
<kbd><kbd>Ctrl</kbd> + <kbd>C</kbd></kbd>) represents multi-key shortcuts clearly. - Monospace rendering: Rendered in monospace font by default for instant visual recognition.
Code Example
<p>Press <kbd>Ctrl</kbd> + <kbd>S</kbd> to save the document.</p>
9. <time> (Machine-Readable Dates)
The Problem
Humans read dates in diverse formats (e.g. "December 25, 2026", "25/12/26"). Search engines and calendar APIs struggle to parse these correctly without semantic annotations.
Why it matters
The <time> element associates human-friendly dates with a standardized ISO date-time string:
- SEO Benefits: Crawlers can index publication dates and schedule timings with 100% confidence.
-
Integration: Browsers and reader apps can parse the
datetimeattribute to add events straight to the user's calendar.
Code Example
<p>The conference is scheduled for <time datetime="2026-12-25">December 25, 2026</time>.</p>
10. <template> (Inert DOM Fragments)
The Problem
Before framework components, creating reusable HTML fragments in vanilla JavaScript required writing long, unsafe innerHTML strings or hiding elements using display: none (which still downloaded active images and executed inline scripts).
Why it matters
The <template> tag holds HTML content that is not rendered when the page loads:
- Inert content: Any media inside (images, video) doesn't load and scripts don't run until the template is instantiated.
-
Safe & Fast: Cloning the template node using
document.importNode()orcloneNode(true)is significantly safer and faster than executinginnerHTML.
Code Example
<!-- The markup below remains hidden and inert until cloned -->
<template id="productCard">
<article style="border: 1px solid #ccc; padding: 15px; border-radius: 8px;">
<h3>Wireless Mouse</h3>
<p>Price: $10.00</p>
<button>Add to Cart</button>
</article>
</template>
<script>
const temp = document.getElementById('productCard');
const container = document.body;
// Clone the template content (true for deep clone)
const clone = temp.content.cloneNode(true);
container.appendChild(clone);
</script>
Wrap-up
These elements show that HTML is not just a layout tool; it is a feature-rich application layer. By choosing semantic HTML first, you:
- Reduce your JS bundle size (making pages load faster).
- Improve accessibility (a11y) out-of-the-box for assistive technologies.
- Boost search engine indexability (SEO).
The next time you reach for a custom JS library to handle common UI interactions, check if native HTML can solve it first!
Happy coding! 🚀
Top comments (0)