Journal
insights

Powerful HTML Elements Most Developers Don’t Use (But Should)

HTML has evolved far beyond simple headings, paragraphs, and <div> elements. Over the past few years, the language has gained powerful semantic elements and built-in interactive components that can replace custom JavaScript, improve accessibility, and make your code significantly cleaner.

Unfortunately, many developers still write HTML as if it’s 2015. They recreate features the browser already provides, rely on unnecessary JavaScript, and miss out on elements specifically designed to solve common interface problems.

In this article, we’ll explore some of the most useful HTML elements that deserve a place in every modern developer’s toolkit. Some of them can simplify your code, others improve accessibility, and a few might completely change how you build user interfaces.

<dialog> : Build Native Modals Without Libraries

For years, creating a modal window meant importing a JavaScript library or writing dozens of lines of custom code to handle opening, closing, keyboard events, focus management, and accessibility. Today, modern HTML provides a built-in solution through the <dialog> element. It dramatically simplifies modal creation while offering features that developers previously had to implement manually. If you’ve been reaching for third-party modal libraries out of habit, the following examples might convince you otherwise.

What is <dialog>?

The <dialog> element is a native HTML component designed specifically for creating dialogs, popups, confirmation windows, alerts, and modal interfaces. Unlike a regular <div>, it already understands concepts such as focus management, keyboard interaction, and modal behavior. This means you spend less time rebuilding common functionality and more time focusing on your application’s user experience.

A minimal dialog looks like this:

<dialog id="myDialog">
    <h2>Welcome!</h2>
    <p>This is a native HTML dialog.</p>

    <button onclick="myDialog.close()">
        Close
    </button>
</dialog>

Although it appears simple, this element already provides much of the functionality developers traditionally implemented with JavaScript libraries.

Opening and Closing a Dialog

Displaying a dialog requires only a single method call. Instead of toggling CSS classes or manipulating multiple elements, the browser provides dedicated methods for opening and closing dialogs.

<button onclick="myDialog.showModal()">
    Open Dialog
</button>

<dialog id="myDialog">
    <h2>Modern HTML</h2>
    <p>Native dialogs are surprisingly easy to use.</p>

    <button onclick="myDialog.close()">
        Close
    </button>
</dialog>

The showModal() method creates a true modal experience, automatically preventing interaction with the rest of the page until the dialog is closed. Keyboard behavior, including the Escape (ESC) key, is also handled natively by the browser, significantly reducing the amount of JavaScript required.

Styling Dialogs

Like any other HTML element, dialogs can be fully customized using CSS. You’re not limited to the browser’s default appearance and can easily integrate them into your existing design system.

dialog {
    border: none;
    border-radius: 16px;
    padding: 2rem;
    max-width: 500px;
    box-shadow: 0 30px 60px rgba(0,0,0,.15);
}

dialog::backdrop {
    background: rgba(0,0,0,.45);
    backdrop-filter: blur(6px);
}

The ::backdrop pseudo-element is particularly useful because it allows you to style the overlay behind the modal without adding extra HTML elements. With only a few lines of CSS, you can create a modern modal that feels every bit as polished as one built with a JavaScript library.

Browser Support

Browser support for <dialog> has improved significantly over the last few years. It is now supported in all major modern browsers, including Chrome, Edge, Firefox, and Safari, making it a practical choice for production websites targeting current browsers.

If your audience still relies on older browsers, lightweight polyfills are available. However, for most modern projects, the native <dialog> element is now stable enough to replace many custom modal implementations while reducing both code complexity and maintenance.

<details> & <summary> : Native Accordions

Accordions are everywhere—from FAQ sections and documentation pages to pricing tables and product descriptions. Traditionally, they were built with JavaScript, requiring developers to manage state, animations, keyboard interactions, and accessibility. Modern HTML eliminates much of that complexity through the <details> and <summary> elements. Together, they provide a semantic, accessible, and lightweight solution that works out of the box while remaining fully customizable with CSS.

Basic Usage

Creating an accordion with native HTML couldn’t be simpler. The <summary> element acts as the clickable heading, while everything inside <details> becomes the expandable content.

<details>
    <summary>What is semantic HTML?</summary>

    <p>
        Semantic HTML uses meaningful elements that describe the purpose of your content instead of relying on generic containers.
    </p>
</details>

This simple structure gives you a fully functional accordion without writing any JavaScript. Users can open and close sections naturally, while browsers automatically handle accessibility features such as keyboard navigation and screen reader support.

Styling

Although native accordions are functional by default, their appearance can be completely customized to match your website’s design language. This makes them suitable for everything from documentation websites to premium landing pages.

details {
    border: 1px solid #ddd;
    border-radius: 12px;
    padding: 1rem;
    margin-bottom: 1rem;
}

summary {
    cursor: pointer;
    font-weight: 600;
}

details[open] {
    border-color: #4f46e5;
    background: #f8f9ff;
}

These styles transform the browser’s default accordion into a polished UI component while keeping the underlying HTML clean and accessible.

Practical Examples

Native accordions work particularly well for FAQ pages, product specifications, API documentation, troubleshooting guides, and any interface where large amounts of content need to remain organized without overwhelming users.

Because the browser handles the expanding and collapsing behavior automatically, developers can focus entirely on content and design. In many projects, replacing custom JavaScript accordions with <details> results in fewer bugs, smaller JavaScript bundles, and a better overall user experience.

<picture> : Responsive Images Made Easy

Images account for a significant portion of most websites’ total page weight, making them one of the biggest opportunities for improving performance. The <picture> element gives developers greater control over which image is displayed based on screen size, browser capabilities, or image format. Instead of serving the same file to every device, you can provide optimized versions tailored to each user’s environment. It’s one of the most valuable HTML elements for building fast, responsive websites.

Art Direction

Responsive design isn’t just about resizing images—sometimes different screen sizes require entirely different compositions. A wide desktop banner may not work well on a narrow mobile screen, where a cropped portrait image communicates the message more effectively.

The <picture> element allows you to define different image sources for different viewport sizes.

<picture>

    <source
        media="(min-width: 992px)"
        srcset="desktop.jpg">

    <source
        media="(min-width: 576px)"
        srcset="tablet.jpg">

    <img
        src="mobile.jpg"
        alt="Responsive Image">

</picture>

The browser automatically selects the most appropriate image based on the current screen size, improving both design quality and user experience.

WebP Fallback

One of the most common uses of <picture> is serving modern image formats like WebP while maintaining compatibility with browsers that may not support them.

<picture>

    <source
        srcset="image.webp"
        type="image/webp">

    <img
        src="image.jpg"
        alt="Example Image">

</picture>

Modern browsers load the lightweight WebP version, while older browsers automatically fall back to the JPEG file. No JavaScript is required, and users receive the best image format their browser supports.

Performance Benefits

Using <picture> effectively can significantly improve website performance. Smaller image files reduce bandwidth usage, decrease loading times, and improve Core Web Vitals—factors that directly influence both user experience and search engine rankings.

Rather than forcing every visitor to download the same large image, the browser intelligently selects the most appropriate version for the current device. The result is a faster, more efficient website that delivers better performance without sacrificing visual quality.

<template> : Reusable HTML Without Rendering

One of the lesser-known but incredibly useful HTML elements is <template>. Many developers repeatedly create DOM elements with JavaScript or hide reusable HTML using CSS, even though browsers already provide a built-in solution for this exact problem. The <template> element allows you to define reusable chunks of HTML that remain invisible until JavaScript explicitly inserts them into the page. If you’re building interactive interfaces, dashboards, or reusable UI components, this element can dramatically simplify your codebase.

What is a Template?

The <template> element stores HTML that isn’t rendered when the page loads. Everything inside it exists in the document but remains inactive until it’s cloned and inserted into the DOM. This makes it ideal for reusable cards, list items, notifications, chat messages, and many other interface components.

<template id="user-card">

    <article class="card">
        <h3>User Name</h3>
        <p>Frontend Developer</p>
    </article>

</template>

Unlike hidden <div> elements, template content isn’t painted, doesn’t affect layout, and doesn’t execute embedded scripts until it’s intentionally used.

JavaScript Integration

The real power of <template> appears when combined with JavaScript. Instead of manually creating dozens of elements with createElement(), you simply clone the template and append it wherever you need it.

const template = document.querySelector("#user-card");

const clone = template.content.cloneNode(true);

document.body.appendChild(clone);

This approach keeps your HTML structure inside HTML and your application logic inside JavaScript, resulting in cleaner, easier-to-maintain code.

Practical Example

Imagine you’re building a team page where every employee card shares the same structure. Rather than repeating identical HTML multiple times or generating every element manually with JavaScript, you can create a single template and reuse it whenever new data becomes available.

This pattern is commonly used in dashboards, chat applications, notifications, product listings, and any interface where components are dynamically generated. Even if you later move to frameworks like React or Vue, understanding native templates provides valuable insight into how reusable UI components work under the hood.

<datalist> : Autocomplete Without JavaScript

Autocomplete fields are incredibly useful for improving user experience. Whether users are searching for cities, selecting programming languages, choosing countries, or entering product names, suggestions reduce typing effort and minimize errors. Surprisingly, many developers still build these features using JavaScript, even though HTML already includes a lightweight solution. The <datalist> element adds autocomplete suggestions to standard input fields while requiring almost no code.

Search Suggestions

The most common use case for <datalist> is providing search suggestions. As users begin typing, the browser automatically displays matching options from the predefined list.

<label for="language">
    Favorite Language
</label>

<input
    id="language"
    list="languages">

<datalist id="languages">
    <option value="HTML">
    <option value="CSS">
    <option value="JavaScript">
    <option value="PHP">
    <option value="Python">
</datalist>

Unlike a traditional dropdown, users aren’t forced to select one of the available values. They can still type completely custom input if necessary, making the experience both flexible and intuitive.

Forms

<datalist> integrates seamlessly into existing forms because it works with standard <input> elements. This makes it useful for country selectors, job titles, product searches, city names, programming languages, or any field where users benefit from intelligent suggestions without losing the ability to enter custom values.

Because the browser handles the suggestion logic automatically, developers avoid writing unnecessary JavaScript while users enjoy a familiar autocomplete experience that behaves consistently across modern browsers.

Browser Support

Support for <datalist> is excellent in modern browsers, including Chrome, Edge, Firefox, and Safari. While browser implementations differ slightly in appearance, the underlying functionality is widely available and suitable for most production websites.

If your project requires advanced filtering, asynchronous search results, or thousands of dynamic suggestions, JavaScript-based autocomplete solutions may still be appropriate. For simple suggestion lists, however, <datalist> offers a fast, lightweight, and highly maintainable alternative.

<meter> : Display Measurements Properly

Developers often represent measurements using generic progress bars or plain text, even when the information isn’t actually showing progress. Password strength, disk usage, battery level, signal quality, and exam scores are all examples of measured values rather than ongoing processes. The HTML <meter> element was designed specifically for these scenarios. It gives semantic meaning to measured values while allowing browsers and assistive technologies to understand exactly what the data represents.

Password Strength

One of the most practical applications of <meter> is displaying password strength during user registration. Instead of using colored text alone, you can present a visual indicator that communicates how secure a password is.

<label>Password Strength</label>

<meter
    min="0"
    max="100"
    value="75">
</meter>

When combined with JavaScript that analyzes password complexity, the meter updates automatically, giving users immediate visual feedback while maintaining semantic HTML.

Storage Usage

Storage indicators are another perfect fit for <meter>. Whether you’re showing cloud storage consumption, server capacity, or project quotas, the element clearly communicates how much of the available capacity has been used.

<label>Storage Usage</label>

<meter
    min="0"
    max="100"
    value="62">
</meter>

Unlike a progress bar, this doesn’t imply that a process is actively running. Instead, it represents the current state of a measurable value, which is exactly what the <meter> element was designed to do.

Battery Level

Battery percentage is another classic measurement rather than a loading process. The <meter> element accurately represents this type of information while providing semantic meaning for browsers and assistive technologies.

<label>Battery Level</label>

<meter
    min="0"
    max="100"
    value="91">
</meter>

Although native browser styling is intentionally simple, <meter> can still be customized with CSS in many browsers to better match your design system. More importantly, using the correct semantic element makes your HTML more meaningful, accessible, and easier to understand for both developers and search engines.

<progress> — Native Progress Bars

Progress indicators are everywhere on the modern web. Whether users are uploading files, waiting for content to load, or tracking the completion of a multi-step process, visual feedback plays an important role in creating a better user experience. Many developers immediately reach for custom progress bars built with <div> elements and JavaScript, but HTML already includes a semantic element designed specifically for this purpose. The <progress> element is lightweight, accessible, and easy to integrate into modern applications while requiring very little code.

Upload Progress

File uploads are one of the most common use cases for <progress>. As the upload progresses, JavaScript simply updates the element’s value attribute, allowing users to understand exactly how much of the process has been completed.

<label>Uploading File...</label>

<progress value="68" max="100"></progress>

Unlike manually built progress bars, the browser already understands the purpose of this element, making it more accessible for screen readers and assistive technologies.

Loading States

Progress indicators are equally useful when users are waiting for lengthy operations such as importing data, generating reports, or processing files. Providing visual feedback reassures users that the application is working instead of appearing frozen.

Sometimes the exact completion percentage isn’t known. In those situations, you can omit the value attribute entirely.

<progress></progress>

The browser automatically displays an indeterminate loading indicator, making it perfect for situations where progress can’t be accurately calculated.

Styling

Although browsers provide a default appearance for <progress>, it can still be customized using CSS to better match your website’s visual identity.

progress {
    width: 100%;
    height: 12px;
}

Many browsers also expose vendor-specific pseudo-elements that allow developers to customize colors and backgrounds even further. While styling capabilities vary slightly between browsers, the semantic benefits of using <progress> remain consistent across all modern platforms.

<time> — Semantic Dates & Times

Dates and times appear throughout almost every website—blog posts, news articles, event pages, product updates, booking systems, and documentation. Most developers simply wrap these values inside a <span> or <div>, but HTML offers a dedicated element that gives this information semantic meaning. The <time> element improves machine readability while helping browsers, assistive technologies, and search engines better understand temporal information. It’s a small addition to your markup that provides benefits far beyond visual presentation.

SEO

Search engines are becoming increasingly sophisticated at understanding structured content. Using the <time> element with a properly formatted datetime attribute provides explicit information about publication dates, event times, and update timestamps.

<time datetime="2026-07-24">
    July 24, 2026
</time>

Although <time> isn’t a replacement for structured data like Schema.org, it strengthens the semantic quality of your HTML and provides search engines with clearer context about your content.

Accessibility

Assistive technologies can interpret the <time> element more accurately than generic containers. This makes dates and times easier to understand for users relying on screen readers or other accessibility tools.

Using semantic HTML consistently also improves the overall structure of your website, making navigation more predictable and helping developers create interfaces that are inclusive by default rather than relying on additional accessibility fixes later.

Machine Readability

One of the biggest advantages of <time> is its machine-readable datetime attribute. Humans can read “July 24, 2026” while software receives a standardized ISO format that’s much easier to process. This becomes particularly valuable for calendars, scheduling systems, event platforms, news websites, and automation tools where software needs to extract dates reliably without guessing their format.

<mark> — Highlight Text Semantically

Highlighting important text is a common design pattern, but many developers achieve it by wrapping content inside a <span> and applying a yellow background with CSS. While this may look correct visually, it doesn’t communicate any semantic meaning. The <mark> element was created specifically to indicate text that is relevant or highlighted within its surrounding context. It’s a small HTML element that improves both readability and semantic clarity while keeping your markup meaningful.

Search Results

One of the most common uses of <mark> is highlighting search keywords inside search results. When users search for a phrase, emphasizing matching words makes it much easier to scan the page and quickly locate relevant information.

<p>
    Modern <mark>CSS</mark> allows developers to replace many JavaScript solutions.
</p>

Unlike a generic <span>, the <mark> element explicitly tells browsers and assistive technologies that this piece of text has been highlighted because of its relevance to the current context. This makes your HTML more expressive while requiring virtually no extra effort.

Important Notes

The <mark> element is equally useful for drawing attention to warnings, updates, recently changed documentation, or particularly important statements within long articles.

<p>
    <mark>Note:</mark> The <code>:has()</code> pseudo-class is now supported in all major modern browsers.
</p>

Rather than relying solely on bold text or color changes, <mark> communicates semantic importance while allowing developers to style highlighted content consistently across an entire website. Combined with thoughtful typography and spacing, it helps readers identify critical information without interrupting the natural reading flow.

<figure> & <figcaption> — Better Images and Code Examples

Images, diagrams, screenshots, and code snippets often require additional context. Unfortunately, many websites simply place a paragraph above or below the content, leaving browsers and assistive technologies with no clear relationship between the two. The <figure> and <figcaption> elements solve this problem by grouping visual content together with its caption in a semantic, meaningful way. They’re simple to use, improve accessibility, and help create cleaner, more maintainable HTML.

Images

The most common use case is pairing an image with a descriptive caption. Instead of separating these elements with unrelated <div> tags, HTML provides a dedicated structure that clearly associates them.

<figure>
    <img src="dashboard.webp" alt="Analytics Dashboard">

    <figcaption>
        A modern analytics dashboard designed using a component-based design system.
    </figcaption>
</figure>

Diagrams

Technical articles frequently include diagrams, wireframes, architecture illustrations, or workflow charts that require explanatory text. Wrapping both the diagram and its description inside <figure> creates a stronger semantic connection and keeps related content grouped together. This approach is especially useful for educational websites, documentation, and tutorials where visuals play an important role in explaining complex ideas.

Code Snippets

Although many developers associate <figure> only with images, it’s equally useful for presenting code examples. A code block can be wrapped inside <figure>, while <figcaption> describes what the snippet demonstrates.

<figure>

<pre><code>
.container {
    display: grid;
}
</code></pre>

<figcaption>
A simple CSS Grid container using the display property.
</figcaption>

</figure>

This structure makes tutorials feel more organized, helps readers understand each example at a glance, and reinforces the semantic relationship between the code and its explanation.

Bonus: Semantic Elements You Should Always Use

Modern HTML isn’t just about replacing <div> elements with more descriptive tags—it’s about giving your content meaning. Semantic elements help browsers, search engines, screen readers, and even other developers understand the structure and purpose of your page without reading your CSS or JavaScript. They improve accessibility, make your code easier to maintain, and create a cleaner document outline. If you’re still wrapping your entire website in dozens of generic <div> elements, it’s time to rethink your HTML structure. The following semantic elements should become part of your everyday workflow.

<main>

The <main> element represents the primary content of a webpage. Every page should have only one <main> element, and it should contain the content that makes the page unique. Navigation menus, headers, sidebars, and footers belong outside of it. Search engines and assistive technologies use this element to quickly identify the most important part of the document, making it especially valuable for accessibility and SEO.

For example, on a blog post, the article itself belongs inside <main>, while the navigation bar and footer remain outside. A clean page structure might look like this:

<body>

    <header>...</header>

    <nav>...</nav>

    <main>

        <article>
            ...
        </article>

    </main>

    <footer>...</footer>

</body>

<nav>

The <nav> element is specifically designed for groups of navigation links. Instead of wrapping menus inside generic containers, <nav> clearly tells browsers that the enclosed links are intended for navigation. This improves semantic structure and helps screen reader users jump directly to navigation areas without scanning the entire page.

Typical examples include the primary navigation menu, sidebar navigation, table of contents, or pagination links.

<nav>

    <a href="/">Home</a>

    <a href="/blog">Blog</a>

    <a href="/about">About</a>

    <a href="/contact">Contact</a>

</nav>

Using <nav> for every group of links isn’t necessary. Reserve it for major navigation sections that help users move around your website.

<aside>

The <aside> element represents content that is related to—but not part of—the main content. Think of it as supporting information. This might include author biographies, advertisements, related articles, newsletter signup forms, category lists, or a table of contents alongside a blog post.

For example, imagine you’re writing a long tutorial. The tutorial itself belongs inside <article>, while a sticky table of contents sits inside an <aside>.

<main>

    <article>
        ...
    </article>

    <aside>
        <h3>Table of Contents</h3>
    </aside>

</main>

This semantic distinction makes your layout easier to understand for both humans and assistive technologies.

<header>

The <header> element introduces a page or a section. It usually contains titles, logos, navigation, breadcrumbs, or introductory information. One common misconception is that a page can only have one <header>. In reality, multiple headers are perfectly valid because individual sections and articles can each have their own introductory content.

For instance, your website may have a global header containing the logo and navigation, while every blog post also includes its own header containing the article title, publication date, and author information.

<article>

    <header>

        <h1>Modern HTML Elements</h1>

        <p>Published on July 24, 2026</p>

    </header>

    ...

</article>

<footer>

The <footer> element represents concluding or supplementary information for a page or section. It commonly contains copyright notices, contact information, legal links, social media icons, or related resources.

Like <header>, <footer> isn’t limited to a single occurrence. An entire webpage may have one footer, while each individual article can also include its own footer containing tags, categories, or author details.

<footer>

    <p>© 2026 Mayaweb. All rights reserved.</p>

</footer>

Using semantic footers helps organize content logically instead of placing everything inside generic containers.

<article>

The <article> element is intended for self-contained pieces of content that can stand on their own. Blog posts, news articles, forum discussions, product reviews, comments, and documentation entries are all excellent candidates.

For example, a blog homepage might display multiple <article> elements, each representing a separate post. If someone copied one of those articles and published it elsewhere, it would still make sense independently—that’s exactly what <article> is designed for.

<article>

    <h2>Modern CSS Features</h2>

    <p>...</p>

</article>

Using <article> appropriately makes your HTML more meaningful and improves the overall semantic structure of your website.

<address>

The <address> element is often misunderstood. It’s not intended for every physical address that appears on a website. Instead, it represents contact information for the author, organization, article, or website. This may include an email address, phone number, physical location, or social media profile.

For example, a company website could place its contact details inside an <address> element within the footer.

<address>

    Email:
    <a href="mailto:hello@example.com">
        hello@example.com
    </a>

</address>

When a <div> Is Still the Right Choice

After learning about semantic HTML, it’s easy to fall into the trap of thinking that every <div> should be replaced with a semantic element. In reality, that’s neither necessary nor recommended. The purpose of semantic HTML is to describe the meaning of content—not to eliminate <div> from your projects. A <div> is simply a generic container, and it’s still the best choice whenever a group of elements has no specific semantic meaning. It’s perfect for layout wrappers, CSS Grid and Flexbox containers, reusable UI components, spacing utilities, animation wrappers, and styling hooks. The mistake isn’t using <div>—it’s using it for everything. A well-structured website typically combines semantic elements for meaningful content with <div> elements for presentation and layout. Experienced developers don’t avoid <div>; they use it intentionally and only when no semantic element better describes the content.

Here are some situations where <div> is still the right tool:

  • Layout Wrappers: Use <div> to group elements for Flexbox or CSS Grid layouts when the container itself doesn’t represent meaningful content.
  • Reusable UI Components: Components such as cards, badges, notifications, loaders, or avatars often use <div> as their outer wrapper because they’re visual building blocks rather than semantic sections.
  • Styling Hooks: Sometimes you simply need an extra element for backgrounds, gradients, borders, overlays, or positioning. A <div> is completely appropriate in these situations.
  • Animation Containers: Wrapping elements for transitions, animations, or transform effects is another excellent use case where semantics add little value.
  • JavaScript Hooks: Interactive components occasionally require wrapper elements for event listeners or DOM manipulation. If the wrapper doesn’t describe content, a <div> remains the cleanest option.
  • Grouping Related Elements Without Semantic Meaning: If a collection of elements doesn’t fit tags like <section>, <article>, <aside>, or <nav>, using a <div> is often the most accurate and maintainable choice.

Final Thoughts

Modern HTML is far more capable than many developers realize. Elements like <dialog>, <picture>, <template>, <datalist>, <meter>, <progress>, and semantic tags such as <article> and <section> allow you to build cleaner, more accessible, and more maintainable websites with less code and fewer dependencies. Rather than reinventing browser features with extra JavaScript or generic containers, embracing these native elements helps you write markup that’s easier to understand—for both humans and machines.

As browsers continue to evolve, investing time in modern HTML is one of the highest-return improvements you can make as a front-end developer. The more you rely on the platform’s built-in capabilities, the simpler, faster, and more future-proof your websites become.

If you enjoy this kind of practical web development content, feel free to explore my other articles where I share modern techniques for building fast, minimal, and scalable websites. And if you’re looking for a custom website that prioritizes clean code, thoughtful UX, and long-term maintainability—not just visual appearance—I’d be happy to help bring your next project to life.