In my page I have two Material Design Component drawers with the same items. One is permanent for desktop/tablet display, the other is hidden/modal for mobile display.
<aside class="mdc-drawer mdc-drawer--permanent">
<div class="mdc-drawer__header">
<h3 class="mdc-drawer__title">App</h3>
<h6 class="mdc-drawer__subtitle">@username</h6>
</div>
<div class="mdc-drawer__content">
<nav class="mdc-list--permanent">@menu_drawer_content</nav>
</div>
</aside>
<aside class="mdc-drawer mdc-drawer--modal">
<div class="mdc-drawer__header">
<h3 class="mdc-drawer__title">App</h3>
<h6 class="mdc-drawer__subtitle">@username</h6>
</div>
<div class="mdc-drawer__content">
<nav class="mdc-list">@menu_drawer_content</nav>
</div>
</aside>
Both are initialised:
modalDrawer = mdc.drawer.MDCDrawer.attachTo(document.querySelector('.mdc-drawer--modal'));
let list = mdc.list.MDCList.attachTo(document.querySelector('.mdc-list--permanent'));
list.wrapFocus = true;
I have javascript that toggles one over the other:
let smallForm = window.matchMedia("(max-width: 767px)").matches;
function resized() {
let smallForm_ = window.matchMedia("(max-width: 767px)").matches;
if (smallForm !== smallForm_) {
smallForm = smallForm_;
changedMedia();
}
}
function changedMedia() {
let drawerButton = $('.mdc-top-app-bar__row > section > button');
if (smallForm) {
$('.mdc-drawer--permanent').hide();
drawerButton.show();
} else {
$('.mdc-drawer--permanent').show();
drawerButton.hide();
modalDrawer.open = false;
}
}
A bug that remains is that selecting an item on one drawer does not select the same item on the other drawer. If I transition from one size to another the selected item will not match the content.
Can I link the two drawers such that selection on one will change the state of the other (especially without triggering events on the "other" drawer or entering a recursive loop cross-notifying loop)?
Edit: Added bounty. Full source.
Figured out how to "undo" the MDC component instantiation so you can use a single drawer and just switch between modal and permanent while preserving the selection of the drawer list item. The important part of the snippet below is to call destroy()
when switching media so that you can modify the drawer class and re-instantiate successfully.
let timeout;
let activeBar;
let activeDrawer;
let activeList;
const actualResizeHandler = () => {
const fixedStyles = () => {
document.body.style = 'display: flex; height: 100vh;';
document.querySelector('.mdc-drawer-app-content').style = 'flex: auto; overflow: auto;';
document.querySelector('.main-content').style = 'height: 100%; overflow: auto;';
document.querySelector('.mdc-top-app-bar').style = 'position: absolute;';
};
const modalStyles = () => {
document.body.removeAttribute('style');
document.querySelector('.mdc-drawer-app-content').removeAttribute('style');
document.querySelector('.main-content').removeAttribute('style');
document.querySelector('.mdc-top-app-bar').removeAttribute('style');
};
const bar = document.querySelector('.mdc-top-app-bar');
const drawer = document.querySelector('.mdc-drawer');
const list = document.querySelector('.mdc-list');
if (typeof activeBar !== 'undefined') {
activeBar.destroy();
}
if (window.matchMedia('(max-width: 767px)').matches) {
if (typeof activeList !== 'undefined') {
activeList.destroy();
}
drawer.classList.add('mdc-drawer--modal');
drawer.insertAdjacentHTML('afterend', '<div class="mdc-drawer-scrim"></div>');
modalStyles();
activeBar = mdc.topAppBar.MDCTopAppBar.attachTo(bar);
activeBar.listen('MDCTopAppBar:nav', () => {
if (typeof activeDrawer !== 'undefined') {
activeDrawer.open = !activeDrawer.open;
}
});
activeDrawer = mdc.drawer.MDCDrawer.attachTo(drawer);
} else {
const scrim = document.querySelector('.mdc-drawer-scrim');
if (scrim) {
scrim.remove();
}
if (typeof activeDrawer !== 'undefined') {
activeDrawer.destroy();
}
drawer.classList.remove('mdc-drawer--modal');
fixedStyles();
activeList = mdc.list.MDCList.attachTo(list);
activeList.wrapFocus = true;
}
};
const resizeThrottler = () => {
if (!timeout) {
timeout = setTimeout(() => {
timeout = null;
actualResizeHandler();
}, 66);
}
};
window.addEventListener('resize', resizeThrottler, false);
actualResizeHandler();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Material Modal / Dismissible Drawer Example</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700">
<link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
</head>
<body>
<aside class="mdc-drawer">
<div class="mdc-drawer__content">
<nav class="mdc-list">
<a class="mdc-list-item mdc-list-item--activated" href="#" tabindex="0" aria-current="page">
<span class="mdc-list-item__text">Item 1</span>
</a>
<a class="mdc-list-item" href="#" tabindex="-1">
<span class="mdc-list-item__text">Item 2</span>
</a>
<a class="mdc-list-item" href="#" tabindex="-1">
<span class="mdc-list-item__text">Item 3</span>
</a>
</nav>
</div>
</aside>
<div class="mdc-drawer-app-content">
<header class="mdc-top-app-bar">
<div class="mdc-top-app-bar__row">
<section class="mdc-top-app-bar__section mdc-top-app-bar__section--align-start">
<button class="material-icons mdc-top-app-bar__navigation-icon mdc-icon-button">menu</button>
<span class="mdc-top-app-bar__title">Title</span>
</section>
</div>
</header>
<main class="main-content">
<div class="mdc-top-app-bar--fixed-adjust">
App Content
</div>
</main>
</div>
</body>
</html>