Building a Side Drawer with Web Standards: Using the Dialog Element

Discover how to build a lightweight, accessible side drawer using native HTML dialog elements instead of heavy JavaScript frameworks. This practical guide shows how web standards can replace complex custom implementations, offering better performance, built-in accessibility, and easier maintenance.

Building a Side Drawer with Web Standards: Using the Dialog Element
Photo by Mike Petrucci / Unsplash

In recent years, we've witnessed a trend in web development that has progressively led us away from web standards.

The rise of JS frameworks has been revolutionary in many ways, but it has also created a culture of reaching for third-party libraries or custom implementations to solve problems that could be addressed with native HTML, CSS, and JavaScript.

Many developers instinctively turn to npm packages or framework-specific solutions without first considering whether the browser already provides a perfectly good solution. This approach leads to bloated applications, lack of accessibility, unnecessary dependencies, and a maintenance burden that could often be avoided.


The Side Drawer Example

Let's take the "side drawer" pattern as an example. This UI component where a panel slides in from the side of the screen is almost everywhere in modern web applications. It appears in many forms: as navigation menus, filter panels, shopping carts, and settings interfaces.

Often it has been , developers have implemented side drawers using third-party JS libraries, framework-specific components, custom implementations with divs, absolute positioning, and event handlers.

These approaches often result in heavy dependencies, accessibility problems, focus management issues, keyboard navigation challenges, inconsistent behavior across sites, high maintenance costs

But what if I told you there's a built-in HTML element that can handle most of this functionality for you?


Dialog Element

The HTML <dialog> element is a standard HTML element designed for modal and non-modal dialogs. It's supported in all modern browsers and provides native functionality that solves many common UI challenges.

While most developers think of the dialog element as only suitable for traditional centered popup dialogs, it can be styled to create a side drawer with minimal effort and with all the accessibility benefits of a native element.


Implementation in 3 Simple Steps

Let's walk through how to create an accessible side drawer using the <dialog> element:

Step 1: Basic HTML Structure

<button id="openDrawer" aria-haspopup="dialog" aria-expanded="false">
    Open Side Drawer
</button>

<dialog id="drawerDialog" aria-labelledby="drawer-title">
    <h2 id="drawer-title">Side Navigation</h2>
    <div class="drawer-content">
        <!-- Your drawer content here -->
    </div>
    <button id="closeDrawer">Close</button>
</dialog>

Step 2: Style It as a Drawer

We need to transform a regular dialog into a side drawer:

dialog {
    /* Position on the right side */
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: auto;
    width: 320px;
    height: 100%;
    
    /* Animation setup */
    transform: translateX(100%);
    transition: transform 0.3s ease-out;
    
    /* Reset default styles */
    margin: 0;
    border: none;
    border-radius: 0;
}

dialog[open] {
    transform: translateX(0);
}

Step 3: Add JavaScript for Interaction

Few line of JS to handle the interaction:

const dialog = document.getElementById('drawerDialog');
const openButton = document.getElementById('openDrawer');
const closeButton = document.getElementById('closeDrawer');
let previousActiveElement;

openButton.addEventListener('click', () => {
    previousActiveElement = document.activeElement;
    openButton.setAttribute('aria-expanded', 'true');
    dialog.showModal();
    closeButton.focus();
});

closeButton.addEventListener('click', () => {
    dialog.close();
    openButton.setAttribute('aria-expanded', 'false');
    previousActiveElement.focus();
});

That's it! With just these three components, we have a functional side drawer that slides in from the right side of the screen.


Built-in Backdrop

One of the most interesting aspects of the <dialog> element is its built-in backdrop. When you call showModal(), the browser automatically:

  1. Creates a semi-transparent overlay behind the dialog
  2. Makes the background content inert (can't be interacted with)
  3. Blocks scrolling of the main page
  4. Provides the proper stacking context

You can even style this backdrop with the ::backdrop pseudo-element:

dialog::backdrop {
    background-color: rgba(0, 0, 0, 0.5);
    animation: fadeIn 0.3s ease forwards;
}

Try implementing all of that yourself, and you'll quickly appreciate the value of it, since usually is one of the most problematic features of the non-standard implementations.


Accessibility as Standard

Using the dialog element also gives you several accessibility features for free:

  • Keyboard dismissal with the Escape key
  • Proper focus management within the dialog
  • ARIA role integration
  • Screen reader announcements

With just a few additional attributes and focus management in JavaScript, you have a fully accessible component that would require significant effort to build from scratch.


Standards First

This side drawer example demonstrates a broader principle that should guide our development practices: check the standards before reaching for alternatives.

Before you install a library or build a custom solution, ask yourself:

  1. Is there a standard HTML element that can solve this problem?
  2. Can I style an existing element to achieve the desired appearance?
  3. Can I combine standard elements with minimal JS to create the functionality I need?

Web standards have evolved significantly, and many UI patterns that previously required complex libraries can now be implemented with native elements, CSS, and a small amount of JavaScript.

By prioritizing standards, you:

  • Reduce bundle sizes and dependencies
  • Create more accessible experiences by default
  • Benefit from browser optimizations
  • Future-proof your code
  • Reduce maintenance overhead

The next time you're tempted to reach for a third-party solution, remember the side drawer example.

Sometimes, the best solution is already built into the platform and you just need to use it creatively.