Skip to main content

Command Palette

Search for a command to run...

🔥 Mastering HTML

Updated
•27 min read
🔥 Mastering HTML
T

I am a developer creating open-source projects and writing about web development, side projects, and productivity.

HTML is a tool for creating web pages. It offers a wide range of functions and a clear structure.

However, many developers have overlooked these features, even though they can greatly enhance web development efficiency and user experience.

But in this article, I will show you the rest of the iceberg and what HTML is capable of.

Semantic HTML isn’t just for Screen Readers - It’s a superpower you are probably ignoring

Let me tell you something I have noticed after conducting dozens (maybe hundreds) of frontend interviews over the years — from junior devs to so-called “staff engineers“ with 10+ years under their belt.

Most of them know semantic HTML exists.
Very few actually
understand it.

They can rattle off that <main>, <section>, and <aside> exist. Some even throw in a <figure> or <time> for good measure.

But when I ask:
“Why would you use a <section> instead of a <div>?”
…I usually get a pause, followed by a vague answer about “accessibility,” or “SEO,” or “structure.”

So, What is Semantic HTML —Really?

Semantic HTML is about meaning, not appearance.

When you use semantic tags, you are telling the browser (and everything that reads HTML — search engines, screen readers, assistive tools, crawlers) what the content represents, not how it looks.

And, guess what? They aren’t just fancier divs.

They play a critical role in how assistive tech, search engines, and even future developers understand your layout.

🎯 Why Should You Care? (Beyond Passing a Lighthouse Audit)

Most frontend engineers treat semantic HTML like flossing.
They know they should do it… but they don’t really feel the urgency.

So let’s break down why it matters:

1. Accessibility That Works Without JavaScript

Screen readers like VoiceOver or NVDA rely on semantic structure to announce content properly.

A <button> is focusable, clickable, and works with keyboard input, by default. A <div> pretending to be a button? You’ll need to simulate all that behavior manually.

TL;DR: If you don’t use semantic elements, you’re breaking accessibility — even if you didn’t mean to.

2. SEO That Understands Your Page

Google’s crawler doesn’t just look at content — it looks at context. Semantic tags help define that context clearly.

  • Using <article> tells Google, “this is a shareable, standalone chunk of info.”

  • Using <header> and <footer> makes the page easier to analyze.

  • Using <main> separates your real content from repetitive elements like navbars.

Semantic HTML helps your content get discovered and ranked more accurately.

3. Better Developer Experience

Imagine coming back to a project after six months and seeing a mess of nested <div class="header">, <div class="main">, <div class="footer">.

Now imagine seeing <header>, <main>, and <footer>.
Cleaner. Clearer. Faster to comprehend.

Semantic HTML is documentation built into your markup.

4. Future-Proof and Standards-Based

Browsers evolve. Assistive tech evolves. SEO rules change.

But semantic HTML is built on standards. Using the right tags today means your site is more likely to work correctly tomorrow, without chasing hacks.

đź§Ş Real-World Analogy: HTML Is the Script of the Web Play

Think of your page as a play.

  • <header> is the opening scene.

  • <main> is the core act.

  • <aside> is like background commentary.

  • <nav> is the stage direction.

  • <footer> is the closing credits.

If you just throw everything into <div>s, it’s like giving actors a blank script. They can try to perform it, but they won’t know what role they’re playing.

Metadata and Meta Tags: The Unsung Heroes of the Web

When you think about building websites, your mind might go straight to HTML elements, beautiful CSS styles, or JavaScript interactivity. But there is a hidden layer of data that powers SEO, social sharing, browser behavior, and accessibility: metadata

What is the Metadata?

Metadata is “data about data“. On the web, it describes the information about the web page rather than the visible content of the page itself.

Examples include:

  • Page title

  • Description

  • Author

  • Language

  • Charset

  • Viewport settings

  • Social sharing info (Open Graph, Twitter Cards)

This data is often invisible to users but essential for search engines, browsers, social media platforms, and assistive technologies.

What are Meta Tags?

Meta Tags are the snippets of HTML placed inside the <head/> of your document to provide metadata. Here’s an example:

<head>
  <title>Learn JavaScript Fast</title>
  <meta name="description" content="A beginner-friendly guide to mastering JavaScript quickly.">
  <meta name="author" content="Jane Developer">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>

Types Of Meta Tags (With Examples)

  1. Basic Meta Tags

âś… Title

Defines the page title shown on the browser tab and in search results.

<title>My Awesome Blog</title>

âś… Description

Helps search engines and social platforms understand what your page is about.

<meta name="description" content="Explore the best web development tips and tricks.">

âś… Author

Credits the content creator.

<meta name="author" content="John Doe">
  1. Viewport Meta Tag (Responsive Design)

Makes your website mobile-friendly.

<meta name="viewport" content="width=device-width, initial-scale=1.0">
  1. Charset

Sets the character encoding. UTF-8 is standard for modern websites.

<meta charset="UTF-8">
  1. Robots Meta Tag

Tells search engines how to crawl or index your page.

<meta name="robots" content="index, follow">
<!-- or -->
<meta name="robots" content="noindex, nofollow">
  1. Social Metadata

Open Graph (Facebook, LinkedIn)

<meta property="og:title" content="Ultimate JavaScript Guide">
<meta property="og:description" content="Everything you need to become a JavaScript pro.">
<meta property="og:image" content="https://example.com/thumbnail.jpg">
<meta property="og:url" content="https://example.com/javascript-guide">

Twitter Cards

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="JavaScript Crash Course">
<meta name="twitter:description" content="Get started with JavaScript the right way.">
<meta name="twitter:image" content="https://example.com/twitter-thumbnail.jpg">
  1. Other Useful Meta Tags

Language

<html lang="en">

HTTP-Equiv (Auto-refresh, page redirect, cache control)

<meta http-equiv="refresh" content="30">

Theme Color (Mobile browsers)

<meta name="theme-color" content="#ffffff">
  1. SEO & Best Practices
  • Always write a unique title and description for each page.

  • Use Open Graph and Twitter Cards for social sharing.

  • Don’t forget the viewport tag for responsive design.

  • Avoid duplicate metadata tags — they confuse crawlers.

  • Use <meta charset="UTF-8"> as early as possible in <head>.

HTML Tips You Must Know About

Lock Background Content with inert

When a modal is open, the rest of the page shouldn’t be clickable.

inert does this in one line while also making it inaccessible to screen readers.

<div id="main-content" inert>
  <!-- your page stuff -->
</div>

<dialog open>
  <p>Hello!</p>
</dialog>
[inert] {
  opacity: 0.5;
}

Real Example 1: Disable a Sidebar While a Dropdown Is Open

Great for dashboards or apps with side menus

<aside id="sidebar">
  <button>Menu Item</button>
  <button>Menu Item</button>
</aside>

<div class="dropdown" id="dropdown">
  <button id="toggle">Open Settings</button>
  <div class="panel" hidden>
    <p>Settings panel content</p>
  </div>
</div>
const sidebar = document.getElementById('sidebar');
const toggle = document.getElementById('toggle');
const panel = document.querySelector('.panel');

toggle.addEventListener('click', () => {
  const isOpen = !panel.hidden;
  panel.hidden = isOpen;
  sidebar.toggleAttribute('inert', !isOpen);
});

Real Example 2: Lock a Form While It’s Submitting

Perfect for preventing double form submissions

<form id="userForm">
  <input type="text" required>
  <button type="submit">Save</button>
</form>

<div id="loading" hidden>Saving…</div>
const form = document.getElementById('userForm');
const loading = document.getElementById('loading');

form.addEventListener('submit', (e) => {
  e.preventDefault();

  form.setAttribute('inert', '');
  loading.hidden = false;

  // Fake submit delay
  setTimeout(() => {
    form.removeAttribute('inert');
    loading.hidden = true;
    alert('Saved!');
  }, 1500);
});

Replace Heavy JS Modals with <dialog>

<dialog> is one of my favorite HTML discoveries.

It gives you a native modal with proper accessibility built in.

const dialog = document.getElementById('myDialog');
dialog.showModal(); // makes page inert + adds backdrop

Closing it is just as easy:

dialog.close();

You don’t need external libraries anymore.

And you can style the backdrop:

dialog::backdrop {
  background: rgba(0,0,0,0.5);
}

Your UI becomes cleaner, faster, and less buggy.

The <template /> Element

The <template /> element is one of those hidden gems in HTML5 that many developers haven’t fully explored.

Without any need for frameworks like React, it serves as a container for holding the HTML content that isn’t rendered on the page immediately. Instead, this content can be cloned and inserted into the DOM later, usually via Javascript.

It’s ideal for scenarios where you need to render content dynamically, like in single-page applications (SPAs) or when your component gets reused multiple times.

Here’s how it works:

<template id="card-template">
    <div class="card">
        <img src="" alt="Image" class="card-img">
        <p class="card-text"></p>
    </div>
</template>

<script>
    const template = document.getElementById('card-template');
    const clone = template.content.cloneNode(true);
    clone.querySelector('.card-img').src = 'image.jpg';
    clone.querySelector('.card-text').textContent = 'This is a dynamic card!';
    document.body.appendChild(clone);
</script>

In this example, we have used the <template /> element to create a reusable card component that can be easily cloned and customized by Javascript.

The <picture /> Element for Responsive Images

The <picture /> element is designed to help developers display different images based on different conditions, such as screen size or resolution.

This feature makes media queries in CSS almost obsolete.

Here’s how you can implement the <picture /> element:

<picture>
    <source srcset="image-small.jpg" media="(max-width: 600px)">
    <source srcset="image-large.jpg" media="(min-width: 601px)">
    <img src="image-default.jpg" alt="Responsive Image">
</picture>

In this example, we have defined different image sources for different screen sizes, ensuring that the appropriate image is loaded depending on the user’s device.

The <datalist /> Element for Enhanced Input Fields

The <datalist /> element is a great addition to HTML5, providing a way to offer predefined options within an input field.

It creates a drop-down list of suggestions that users can choose from, making forms more interactive and user-friendly.

Let’s see how to use the <datalist /> element in a search input field:

<input type="text" list="fruits">
<datalist id="fruits">
    <option value="apple"></option>
    <option value="orange"></option>
    <option value="banana"></option>
</datalist>

The <output /> Element for Display Calculation Results

The <output /> element is a great tool in HTML5 for displaying the results of calculations or user actions.

It’s particularly useful in interactive forms or web applications where you want to show immediate feedback without relying on Javascript.

Here is how the <output /> element can be used:

<form oninput="result.value=parseInt(a.value)+parseInt(b.value)">
    <input type="number" id="a" value="50"> +
    <input type="number" id="b" value="100">
    = <output name="result" for="a b">150</output>
</form>

In this example, the <output /> element has displayed the sum of two numbers in real time.

Create clickable emails, phone calls, and SMS links using HTML:

<!-- Email link -->
<a href="mailto:name@example.com"> Send Email </a>

<!-- Phone call link -->
<a href="tel:+1234567890"> Call Us </a>

<!-- SMS link -->
<a href="sms:+1234567890"> Send SMS </a>

Creating Collapsible Content - <details />

You can use the <details> and <summary> tags, when you want to include collapsible content on your web page.

The <details /> tag creates a container for hidden content, while the <summary /> tag provides a clickable label to toggle the visibility of that content.

<details>
    <summary>Who to follow?</summary>
    Halim Shams
</details>

Utilizing Semantic Elements

The elements mentioned above fall under an umbrella term: semantic HTML. Semantic HTML gives meaning to your HTML content—not only to users but also to browsers, crawlers, and accessibility tools.

Not everyone can see the screen or use devices such as a mouse to navigate the web. Instead, they rely on assistant technologies to interpret the content.

Also, search engines can find relevant content more easily by traversing through semantic HTML. That’s why it should be one of your top priorities when you are building a website.

You also don’t want your website to be just a bunch of divs because div elements don't mean anything to the browser in terms of content—for a browser, they’re just a division element to separate the content.

Choose semantic elements over non-semantic elements for your websites. They make your code meaningful and improve structure, accessibility, and SEO.

Grouping Form Elements - <fieldset>

Use the <fieldset> tag to group related elements in a form and the <legend> tag with <fieldset> to define a title for the <fieldset> tag.

This is useful for creating more efficient and accessible forms:

<form>
   <fieldset>
      <legend>Personal details</legend>
      <label for="firstname">First name:</label>
      <input type="text" id="firstname" name="firstname" />
      <label for="email">Email:</label>
      <input type="email" id="email" name="email" />
      <label for="contact">Contact:</label>
      <input type="text" id="contact" name="contact" />
      <input type="button" value="Submit" />
   </fieldset>
</form>

Enhancing Dropdown Menus - <optgroup>

You can use the <optgroup> tag to group related options in a <select> HTML tag.

This can be used when you are working with a large dropdown menu and a long list of options:

<select>
   <optgroup label="Fruits">
      <option>Apple</option>
      <option>Banana</option>
      <option>Mango</option>
   </optgroup>
   <optgroup label="Vegetables">
      <option>Tomato</option>
      <option>Broccoli</option>
      <option>Carrot</option>
   </optgroup>
</select>

Display Text as Subscript and Superscript

The <sub> and <sup> elements can be used to display the text as subscript and superscript respectively:

You can use the <base> tag to define the base URL for all relative URLs on the web page.

This is handy when you want to create shared starting points for all relative URLs on a web page, making it easier to navigate and load resources.

<head>
   <base href="https://shefali.dev" target="_blank" />
</head>
<body>
   <a href="/blog">Blogs</a>
   <a href="/get-in-touch">Contact</a>
</body>

<mark />

<mark /> is a tag used to highlight or mark a part of a text. This tag supports all HTML global attributes, the default color is black with a yellow background color.

<!DOCTYPE html>
<html>
    <head> </head>
    <body>
        <p>
            in this paragraph, there is a text
            <!-- 
                by default => (
                    color: black;                
                    background-color: yellow;
                )
             -->
            <mark>highlighted</mark>
        </p>
    </body>
</html>

Output:

You can change the yellow color like this:

<mark style="background-color:green">highlighted</mark>

Output:

<address />

<address /> is a tag that displays contact information like the email and phone number of the author of a document or an article, additionally, it supports all HTML global attributes.

<!DOCTYPE html>
<html>
    <head> </head>
    <body>
        <address>
            Posted by
            <a href="https://t.me/AyaBouchiha"> Aya Bouchiha </a>
            <br />
            Email Address:
            <a href="mailto:developer.aya.b@gmail.com">
                developer.aya.b@gmail.com
            </a>
            <br />
            Phone Number:
            <a href="tel:+212600000000">+212600000000 </a>
            <br />
            Morocco, Azemmour
        </address>
    </body>
</html>

Output:

<noscript />

<noscript />: This tag can be inside a head or a body tag, it displays alternate HTML contents if the script type is not supported or if the browser has scripting disabled. if not the tag will not display the alternate HTML. But you have to be careful, <noscript /> tag sometimes impacts the SEO due to writing the same sentence on every page of your website… solutions & more details.

<!DOCTYPE html>
<html>
    <body>
        <script>
            alert("javascript is supported in your browser :)");
        </script>
        <noscript> Javascript is not supported in your browser :( </noscript>
    </body>
</html>

Output:

<time />

<time />: represent a specific period in time. It may include the date time attribute to translate dates into a machine-readable format, allowing for better search engine results or custom features such as reminders. (support all HTML global attributes). more details

<html>
    <head></head>
    <body>
        <p>
            The next meeting will be held on 
            <time datetime="2021-11-25">
                Nov 25
            </time>
            in Rabat
        </p>
    </body>
</html>

Output:

<var />

<var />: supports all HTML global attributes and indicates the name of mathematical variables such as x and y, by default its text content is italic.

<html>
    <head></head>
    <body>
        <div>
            <!--
                by default (
                    var {
                        font-style: italic;
                    }
                )
            -->
            <p>Ex:1 solve this equation:</p>
            <var>4x</var> + <var>2y</var> = 12
        </div>
    </body>
</html>

Output:

The <code/> Tag

The <code /> tag is extremely useful for displaying code blocks. You could use CSS and a normal <p> element to make it look like a code block, but why do that when the <code> tag exists for this exact use case?

<p>In JS we have <code>console.log("Heyo!")</code></p>

The <kbd /> Tag

It’s similar to the code tag, we have the <kbd /> tag, also known as the keyboard tag. It is used to showcase keyboard input.

<p>Press <kbd>Ctrl</kbd> to start.</p>

The <abbr> Tag

First up, the <abbr> tag, also known as the abbreviation tag. This one is used when you want to display the meaning of an acronym or abbreviation.

<abbr title="A type of snake">Python</abbr>

Notice the title attribute used with the <abbr> tag. This works with every tag. Now, when you hover your cursor over that abbreviation, it shows the title that you set. I recommend putting this on buttons or icons for enhanced accessibility.

The <aside> element

You can use this element for any content not directly related to the page's main content. It works well for displaying advertisements, related posts, promotional content, blockquotes, nav elements, and so on.

<main>
    <h2>Post</h2>
    <p>This post is about a breed of dogs.</p>
    <aside>
        <p>Learn more about cats.</p>
    </aside>
</main>

For example, in the above snippet, the post is mainly about dogs and their breeds. But if you wrote an article about cats and you wanted to link to it from the dog article, then you could use an aside element to mention it. The content in the aside element can be tangentially related to the page.

The HTML specification provides some good examples of how to use the <aside> element.

The <search> Element

You can use the <search> element as a container for elements dealing with search or filtering. For example, a form sending a POST request to get search results or a search component relying on Javascript or filtering.

// search component relying on JavaScript
<search>
    <input type="text" id="searchInput">
    <div id="results"></div>
</search>

Here is another example:

<search>
    <form action="search.js" method="POST">
        <input type="text" id="searchInput">
        <button type="submit">Search</button>
    </form>
</search>

In both of the above examples, the elements wrapped within the search element contributes to a site's search functionality.

You should use this element because it provides semantic values to the browser and accessibility tools such as screen readers.

The <progress> element

As the name suggests, the native progress element in HTML tracks the progress of a task.

You can use this element in two ways: determinately and indeterminately. A determinate progress bar knows where it currently is, and if the max value is specified, you can also figure out how much more is left.

To create a determinate progress bar, you need to specify the value attribute. The default range of the value is from 0.0 to 1.0. But you can also specify the custom max value which has to be a valid floating point number.

<progress value="0">0%</progress>
<!-- or -->
<progress value="0" max="100">0%</progress>

<map> and <area>

<map> and <area> — powerful combo to create clickable areas in images:

We call clickable images like these image maps:

Not using HTML Entities

Please don't copy and paste symbols like this: ™, ℠, ®, and ©.

Instead, use these:

&nbsp; -> for blank space
&reg; -> for trademark
&copy; -> for copyright
and etc.

Powerful HTML Attributes

Spellcheck

This attribute ensures that the browser checks spelling within specific elements, such as input fields or text areas, without requiring Javascript. It’s particularly useful for forms or content where accuracy matters.

   <textarea spellcheck="true"></textarea>

Download

The download attribute allows users to download resources directly when clicking on a link. It’s handy for providing downloadable content like images, documents, and media files without Javascript.

<a href="path/to/file.pdf" download>Download PDF</a>

Video Thumbnail (Poster)

By using the poster attribute within the <video> element, you can specify an image to display as a placeholder before the video starts playing. This mimics the functionality of a video thumbnail, enhancing user experience.

<video controls poster="path/to/thumbnail.jpg">
       <source src="path/to/video.mp4" type="video/mp4">
       Your browser does not support the video tag.
   </video>

Translate

Employing the translate attribute, you can specify whether an element’s content should be translated when a web page is translated into another language. Setting it to “no“ preserves the original content, useful for brand names or specific terms.

   <h1 translate="no">Your Company Name</h1>

Autocomplete

The autocomplete attribute enables or disables the autocomplete functionality for input fields, providing control over whether the browser should suggest previously entered values. This can enhance user convenience and streamline form submission.

   <input type="text" autocomplete="on">

Form Validation With HTML5 Attributes

HTML5 has introduced built-in form validation attributes such as required, pattern, minlength, and maxlength.

These attributes have allowed you to enforce input rules directly in the HTML, reducing the need for complex Javascript validation.

Here’s an example of a form with HTML5 validation:

<form>
    <label for="username">Username:</label>
    <input type="text" id="username" name="username" required minlength="4" maxlength="20">

    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required pattern="[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$">

    <input type="submit" value="Submit">
</form>

Supporting Multiple Selections

You can use the multiple attributes with the <input> and <select> elements to allow users to select multiple values at once.

<input type="file" multiple />
<select multiple>
    <option value="java">Java</option>
    <option value="javascript">JavaScript</option>
    <option value="typescript">TypeScript</option>
    <option value="rust">Rust</option>
</select>

Control Image Loading

The loading attribute of the <img> element can be used to control how the browser loads the image. It has three values: “eager“, “lazy“, and “auto“.

<img src="picture.jpg" loading="lazy">

Enabling Content Editing

Use the contenteditable attribute to specify whether the element’s content is editable or not.

It allows users to modify the content within the element.

<div contenteditable="true">
   You can edit this content.
</div>

Ensuring Accessibility

The alt attribute specifies the alternate text for an image if the image can not be displayed.

Always include descriptive alt attributes for images to improve accessibility and SEO.

<img src="picture.jpg" alt="Description for the image">

You can use the target attribute to specify where a linked resource will be displayed when clicked.

<!-- Opens in the same frame -->
<a href="https://shefali.dev" target="_self">Open</a>

<!-- Opens in a new window or tab -->
<a href="https://shefali.dev" target="_blank">Open</a>

<!-- Opens in the parent frame -->
<a href="https://shefali.dev" target="_parent">Open</a>

<!-- Opens in the full body of the window -->
<a href="https://shefali.dev" target="_top">Open</a>

<!-- Opens in the named frame -->
<a href="https://shefali.dev" target="framename">Open</a>

Providing Additional Information

The title can be used to provide additional information about an element when users hover on it.

<p title="World Health Organization">WHO</p>

Accepting Specific File Types

You can use the accept attribute to specify the types of files accepted by the server (only for file types). This is used with the <input> element.

<input type="file" accept="image/png, image/jpeg" />

Optimizing Video Loading

You can make video files load faster for smoother playback by using the preload attribute with <video> element.

<video src="video.mp4" preload="auto">
   Your browser does not support the video tag.
</video>

Capture Attribute

It is used to determine which source to use when receiving media (video, photo, audio) files from the user.

It is usually used with the input element and its value allows users to capture content directly by opening their device’s camera, microphone, or other media sources.

It takes two values to control input: capture:user uses the user’s front camera or micro as an input, capture:environment uses the user’s back camera to capture the input data.

Auto Refresh

You can set your website to refresh after a given amount of time from the head tag. You just need to set up that in the head tag. The code above refreshes the page every 10 seconds.

99% of Developers Don’t Know These ARIA Attributes Exist

Accessibility is no longer optional, and honestly, these tools we have now have made it easier to build websites that work with everyone. RIA attributes are at the heart of this, and they are much more powerful than most developers realize.

What Exactly Are ARIA Attributes?

ARIA stands for Accessible Rich Internet Applications. At its core, ARIA give you a way to communicate with assistive technologies like screen readers. When you build a custom dropdown or a fancy model, your code knows what it is, but screen readers don’t. ARIA fill that gap.

Think of it this way, you create a beautiful tabbed interface using divs and CSS. Visually, it’s perfect, but someone using a screen reader has no idea of those tabs. Add the right ARIA attributes, and suddenly, a screen reader understands the entire integration pattern.

Why This Actually Matters?

Over a billion people worldwide have some form of disability, which is approximately 15-16% of the global population. Many rely on screen readers, voice control, keyboard navigation, and other assistive technologies just to use the web. Without proper ARIA implementation, your site might look amazing but completely unusable to them

Accessibility isn’t just about compliance and avoiding lawsuits (though those are real concerns). Accessible websites are better websites. They are more semantic, easy to navigate with the keyboard, have better structures, and perform better in search engines as well.

The First Rule of ARIA

Before we go deeply into this massive list, you need to know this: semantic HTML always comes first.

Don’t use <div role="button"> when <button> exists. Don't reinvent the wheel with ARIA when HTML already does the job. Native elements come with built-in accessibility, keyboard support, and expected behaviors. ARIA is for filling the gaps when HTML falls short.

Practical Examples You’ll Use Daily

Here’s how this stuff works in real code.

Example 1: Custom Toggle Button

<div role="button" 
     tabindex="0" 
     aria-pressed="false"
     onclick="this.setAttribute('aria-pressed', this.getAttribute('aria-pressed') === 'false')">
  Dark Mode</div>

Example 2: Accessible Modal Dialog

<div role="dialog" 
     aria-modal="true" 
     aria-labelledby="dialog-title"
     aria-describedby="dialog-desc">
  <h2 id="dialog-title">Delete Item?</h2>
  <p id="dialog-desc">This action cannot be undone.</p>
  <button>Delete</button>
  <button>Cancel</button>
</div>

Example 3: Form Validation

<label for="email">Email Address</label>
<input type="email" 
       id="email" 
       aria-required="true"
       aria-invalid="true" 
       aria-describedby="email-error">
<span id="email-error" role="alert">
  Please enter a valid email address
</span>

Example 4: Expandable Section

<button aria-expanded="false" aria-controls="content-panel">
  Show More Details
</button>
<div id="content-panel" hidden>
  Additional content here...
</div>

Example 5: Live Search Results

<label for="search">Search Products</label>
<input id="search" 
       type="search" 
       aria-controls="results"
       aria-describedby="results-count">
<div id="results" 
     role="region" 
     aria-live="polite">
  <span id="results-count">12 products found</span>
  <!-- Results list here -->
</div>

HTML5 Semantic Tags: 7 Elements You Are Probably Using Wrong

Semantic HTML is not a theory,

It’s a map that makes your site usable.

Most teams sprinkle tags like seasoning and call it a day.

Screen readers get lost, search engines guess, and CSS becomes brittle.

I have reviewed a codebase where the markup looked modern and still failed users.

The problem was not divs.

The problem was how the semantic elements were used.

  1. <main> — one per page, no nested <main>

The mistake: multiple <main> tags or nesting them inside layout wrappers.
Why it hurts: screen readers jump straight to <main> to skip Chrome; duplicates destroy that jump.

Use it like this

<body>
  <header>…</header>
  <nav aria-label="Primary">…</nav>

  <main id="content">
    <!-- The unique primary content of this document -->
  </main>

  <footer>…</footer>
</body>

Rules that hold up in production:

  • Only one <main> per document.

  • It must not be inside <article>, <aside>, <header>, <footer>, or <section>.

  • Give it a stable id if you use “Skip to content” links.

  1. <section> - only with a heading

The mistake: using <section> as a fancy <div>.
Why it hurts: sections without headings break the document outline and confuse navigation.

Fix

<section aria-labelledby="billing-h">
  <h2 id="billing-h">Billing</h2>
  <p>Update your payment method.</p>
</section>

If you do not have a natural heading, you probably want a <div>.

  1. <article> — self-contained, shareable units

The mistake: wrapping random parts of a page in <article>.
Why it hurts: <article> tells crawlers and assistive tech that this block could stand alone in a feed or an email.

Use it for things like:

  • Blog posts, news items, forum threads

  • Product reviews, comment cards, changelog entries

Fix

<article>
  <header>
    <h1>Release 2.1</h1>
    <p>Published by Dev Team</p>
  </header>

  <p>We added keyboard shortcuts and improved search.</p>

  <footer>
    <a href="#comments">12 comments</a>
  </footer>
</article>

If the content makes sense outside this page, <article> is right. If not, prefer <section> or <div>.

  1. <header> — local intros, not only site chrome

The mistake: treating <header> as the global top bar only.
Why it hurts: you miss useful structure inside articles and sections.

You can place a <header> inside <article> or <section> to group the heading and related intro controls.

<article>
  <header>
    <h2>Keyboard Shortcuts</h2>
    <p>Save minutes every day with these keys.</p>
  </header>
  <p>Press “?” to open the cheat sheet.</p>
</article>

Tip: keep only introductory elements in <header>; actions and content belong below.

  1. <footer> — closes a scope, not a place for stray links

The mistake: one global footer and nothing else.
Why it hurts: articles and cards lose a semantic place for metadata and actions.

You can and should use <footer> inside components that read like documents.

<article>
  <h2>How We Cache</h2>
  <p>We use a two-tier strategy with CDN and Redis.</p>

  <footer>
    <p>Last updated: <time datetime="2025-03-19">March 19, 2025</time></p>
    <a href="/caching#discussion">Join the discussion</a>
  </footer>
</article>

Keep the global page footer for site-wide navigation and legal links.

  1. <nav> — Label it and keep it to navigation

The mistake: wrapping any list of links in <nav>.

Why it hurts: assistive tech expects navigation landmarks; stuffing random links dilutes signal.

Use <nav> for primary, secondary, breadcrumb, or in-page navigation. Always label it.

<nav aria-label="Breadcrumb">
  <ol>
    <li><a href="/">Home</a></li>
    <li><a href="/docs">Docs</a></li>
    <li aria-current="page">API</li>
  </ol>
</nav>

Good patterns:

  • Use aria-current="page" or "step" for the active item.

  • Prefer lists (ul/ol) for grouped nav links.

  1. <aside> — relevant but not required

The mistake: using <aside> for main content columns or generic sidebars that hold core tasks.

Why it hurts: Some users skip asides by default. If it is required to complete the task, it is not an aside.

Right uses

  • Tips, callouts, related links

  • Pull quotes, promo modules, complementary charts

<main>
  <article>
    <h1>Set Up Two-Factor Authentication</h1>
    <p>Open Settings → Security and follow these steps.</p>
  </article>

  <aside aria-label="Security Tips">
    <h2>Security Tips</h2>
    <ul>
      <li>Use a password manager.</li>
      <li>Store backup codes offline.</li>
    </ul>
  </aside>
</main>

14 Modern HTML + JavaScript Combos That Feel Like Magic in 2025

HTML and JavaScript keep getting better together. If you’ve been building for the web over the past few years, you know how far the platform has evolved. We’ve reached a point where many features that once required heavy frameworks or third-party libraries now work natively — cleanly, efficiently, and beautifully.

Let’s dive in 👇

  1. <dialog> + JavaScript Modal Controls

Why it matters: The <dialog> element eliminates the need for heavy modal libraries. With native methods like show(), showModal(), and close(), you can manage modals seamlessly.

<dialog id="myModal">
  <p>This is a native modal!</p>
  <button id="close">Close</button>
</dialog>

<button id="open">Open Modal</button>
<script>
const modal = document.getElementById('myModal');
document.getElementById('open').onclick = () => modal.showModal();
document.getElementById('close').onclick = () => modal.close();
</script>

Right: Use <dialog> for lightweight modals.
Wrong: Building modals from scratch with tons of CSS and JS overhead.

  1. <details> + <summary> for Expandable Sections

Why it matters: No need for extra JavaScript to create collapsible FAQs or sections.

<details>
  <summary>What’s new in HTML5?</summary>
  <p>Semantic tags, native media, and form enhancements.</p>
</details>

Right: Let the browser handle expand/collapse logic.
Wrong: Adding JS just to toggle simple visibility.

  1. Intersection Observer + Lazy Loading

Why it matters: You can now control when elements enter the viewport without scroll event listeners.

const images = document.querySelectorAll('img[data-src]');
const observer = new IntersectionObserver(entries => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      entry.target.src = entry.target.dataset.src;
      observer.unobserve(entry.target);
    }
  });
});
images.forEach(img => observer.observe(img));

Right: Use Intersection Observer for lazy loading or animations.
Wrong: Using scroll handlers that trigger on every pixel move.

  1. <template> + Cloning Elements

Why it matters: It’s perfect for rendering repetitive content like lists or cards.

<template id="card">
  <div class="card">
    <h3></h3>
    <p></p>
  </div>
</template>

<div id="container"></div>
<script>
const template = document.getElementById('card');
const container = document.getElementById('container');
['HTML', 'CSS', 'JS'].forEach(topic => {
  const clone = template.content.cloneNode(true);
  clone.querySelector('h3').textContent = topic;
  clone.querySelector('p').textContent = 'Learn ' + topic;
  container.appendChild(clone);
});
</script>

Right: Reuse templates for dynamic content.
Wrong: Creating repetitive markup manually with innerHTML.

  1. <input type="color"> + JS Customization

Why it matters: It gives users a native color picker without dependencies.

<input type="color" id="picker">
<div id="preview">Preview Text</div>

<script>
const picker = document.getElementById('picker');
const preview = document.getElementById('preview');
picker.oninput = () => preview.style.color = picker.value;
</script>

Right: Enhance native elements with JS.
Wrong: Using third-party color picker plugins for basic use cases.

  1. Clipboard API + Buttons

Why it matters: Copy-to-clipboard is now natively supported.

<button id="copy">Copy</button>
<p id="text">Copy this text!</p>

<script>
copy.onclick = async () => {
  await navigator.clipboard.writeText(text.textContent);
  alert('Copied!');
};
</script>

Right: Use navigator.clipboard for simple copy features.
Wrong: Using hidden textareas or execCommand hacks.

  1. fetch() + async/await

Why it matters: Simplifies API requests without heavy libraries like Axios.

async function getUser() {
  const res = await fetch('https://jsonplaceholder.typicode.com/users/1');
  const user = await res.json();
  console.log(user);
}
getUser();

Right: Use async/await for clean, readable async code.
Wrong: Callback hell or unnecessary dependencies.

  1. <progress> + JS Updates

Why it matters: Native progress bars are accessible and easy to update dynamically.

<progress id="bar" value="0" max="100"></progress>

<script>
let value = 0;
const bar = document.getElementById('bar');
setInterval(() => {
  value = (value + 10) % 110;
  bar.value = value;
}, 1000);
</script>

Right: Use <progress> for native UI.
Wrong: Using divs with CSS for progress when native exists.

  1. localStorage + JSON Handling

Why it matters: Perfect for persisting user preferences without backend calls.

const user = { theme: 'dark', fontSize: 16 };
localStorage.setItem('user', JSON.stringify(user));
const saved = JSON.parse(localStorage.getItem('user'));

Right: Store structured data as JSON.
Wrong: Storing plain strings without structure.

  1. <video> + JS Controls

Why it matters: The native video API lets you control playback without external players.

<video id="vid" width="320" controls>
  <source src="video.mp4" type="video/mp4">
</video>
<button onclick="vid.play()">Play</button>
<button onclick="vid.pause()">Pause</button>

Right: Use native controls for performance and accessibility.
Wrong: Using bloated video plugins for simple playback.

  1. <canvas> + JS Drawing

Why it matters: Perfect for visualizations or custom animations.

<canvas id="art" width="200" height="200"></canvas>
<script>
const ctx = art.getContext('2d');
ctx.fillStyle = 'orange';
ctx.fillRect(20, 20, 150, 100);
</script>

Right: Use canvas for dynamic graphics.
Wrong: Using DOM elements for visual-heavy tasks.

  1. <meter> + Live Stats

Why it matters: Displays real-time data like scores or battery.

<meter id="score" min="0" max="100" value="45"></meter>
<script>
setInterval(() => score.value = Math.floor(Math.random()*100), 1000);
</script>

Right: Use <meter> for measurable quantities.
Wrong: Styling <div>s to fake meters.

  1. CSS Variables + JS Interaction

Why it matters: JS can manipulate CSS variables live, improving theme switching.

<style>
  :root { --bg: #fff; }
  body { background: var(--bg); }
</style>
<button id="dark">Dark Mode</button>

<script>
dark.onclick = () => {
  document.documentElement.style.setProperty('--bg', '#222');
};
</script>

Right: Use CSS vars for dynamic theming.
Wrong: Overwriting inline styles repeatedly.

  1. Web Share API + Buttons

Why it matters: Share links natively from web apps.

<button id="share">Share This Page</button>
<script>
share.onclick = async () => {
  await navigator.share({ title: 'Frontend Magic', url: location.href });
};
</script>

Right: Use native sharing for mobile-first UX.
Wrong: Forcing users to copy URLs manually.

Final thoughts

If this article was helpful and surprised you with the power that HTML truly has, let me know in the comments.

References

https://levelup.gitconnected.com/top-5-html-features-youre-not-using-but-should-be-73f8544c2116

https://dev.to/devshefali/21-html-tips-you-must-know-about-55j7?context=digest

https://dev.to/ayabouchiha/5-html-tags-that-almost-nobody-knows-5p5

https://halimshams.medium.com/the-hidden-html-tags-you-should-be-using-21c413a8fb3a

https://www.freecodecamp.org/news/less-common-html-tags/?ref=dailydev

https://medium.com/coding-beauty/rare-html-tags-9ed55211acd5

https://medium.com/developers-corner/5-html-tips-probably-you-dont-know-3dc68d9b5214

https://dev.to/ashishxcode/5-powerful-html-attributes-that-dont-require-javascript-lfb?ref=dailydev

https://medium.com/web-tech-journals/semantic-html-isnt-just-for-screen-readers-it-s-a-superpower-you-re-probably-ignoring-387af47d6fd8

https://medium.com/@sonampatel_97163/html5-semantic-tags-7-elements-youre-probably-using-wrong-397430906fac

https://pixicstudio.medium.com/99-of-developers-dont-know-these-aria-attributes-exist-8bbc57647818

http://medium.com/@theabhishek.040/modern-html-javascript-combos-2025-34686591563a

https://habtesoft.medium.com/metadata-and-meta-tags-the-unsung-heroes-of-the-web-80b1e17e2ccb

https://medium.com/@TusharKanjariya/the-html-tricks-i-learned-the-hard-way-2194edcbc9b2

More from this blog

T

Tuanhadev Blog

30 posts

đź‘‹ Hi there, I'm tuanhadev! I am a developer creating open-source projects and writing about web development, side projects, and productivity.