Skip to content

Drawer

Side panel using the native HTML <dialog> element. Slides in from the left or right.

<dialog class="af-drawer" id="my-drawer">
  <div class="af-drawer-header">
    <h3>
      Navigation
    </h3>
    <button class="af-btn af-btn-icon" aria-label="Close"
    onclick="this.closest('dialog').close()">
      ×
    </button>
  </div>
  <div class="af-drawer-body">
    <ul class="af-side-nav">
      <li class="af-side-nav-item">
        <a href="#" class="af-side-nav-link" aria-current="page">
          Dashboard
        </a>
      </li>
      <li class="af-side-nav-item">
        <a href="#" class="af-side-nav-link">
          Settings
        </a>
      </li>
      <li class="af-side-nav-item">
        <a href="#" class="af-side-nav-link">
          Account
        </a>
      </li>
    </ul>
  </div>
</dialog>
<button class="af-btn"
onclick="document.getElementById('my-drawer').showModal()">
  Open Drawer
</button>

Add af-drawer-right to open from the right edge:

<dialog class="af-drawer af-drawer-right" id="filters-drawer">
  <div class="af-drawer-header">
    <h3>
      Filters
    </h3>
    <button class="af-btn af-btn-icon" aria-label="Close"
    onclick="this.closest('dialog').close()">
      ×
    </button>
  </div>
  <div class="af-drawer-body">
    <div class="af-stack af-gap-md">
      <div class="af-field">
        <label class="af-label" for="filter-status">
          Status
        </label>
        <select id="filter-status" class="af-select">
          <option>
            All
          </option>
          <option>
            Active
          </option>
          <option>
            Archived
          </option>
        </select>
      </div>
      <div class="af-field">
        <label class="af-label" for="filter-date-range">
          Date range
        </label>
        <input id="filter-date-range" class="af-input" type="date">
      </div>
      <button class="af-btn">
        Apply Filters
      </button>
    </div>
  </div>
</dialog>
<button class="af-btn"
onclick="document.getElementById('filters-drawer').showModal()">
  Open Filters
</button>

Same as dialog. Open with showModal(), close with close().

const drawer = document.getElementById('my-drawer');

drawer.showModal();
drawer.close();
ClassPurpose
af-drawerThe <dialog> element. Opens from the left by default.
af-drawer-rightModifier. Opens from the right instead.
af-drawer-headerHeader row with title and close button
af-drawer-bodyScrollable content area
drawer.addEventListener('click', (e) => {
if (e.target === drawer) drawer.close();
});

Same accessibility model as dialog. Native <dialog> with showModal() marks the page as inert and provides ESC key and body scroll lock. Focus trapping and focus restoration require supplemental JS for full cross-browser reliability.