Search code examples
javascriptjquerycssmdc-components

Giving ltr to MDC Switch not working inside a rtl MDC Drawer


The MDC Switch inside an MDC Drawer (RTL) has a thumb that is placed on the right instead of the left when it is switched on. I want the thumb to be at the left when it's off and at the right when it's on (I want the thumb to move from the left side to the right side).

I have tried tried adding dir="ltr" attribute to the mdc-switch element, but no luck.

window.mdc.autoInit();
var drawer = mdc.drawer.MDCDrawer.attachTo(document.querySelector('.mdc-drawer'));

var button = document.querySelector('button');
mdc.ripple.MDCRipple.attachTo(button);
button.addEventListener('click', function() {
  drawer.open = true;
});
<link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.css" rel="stylesheet"/>
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.js"></script>
<aside class="mdc-drawer mdc-drawer--modal" dir="rtl">
  <div class="mdc-drawer__content">
    <nav class="mdc-list">
      <div class="mdc-form-field">
        <div class="mdc-switch" data-mdc-auto-init="MDCSwitch" id="mdcAutoScroll" dir="ltr">
          <div class="mdc-switch__track"></div>
          <div class="mdc-switch__thumb-underlay">
            <div class="mdc-switch__thumb">
              <input type="checkbox" id="autoscroll-switch" class="mdc-switch__native-control" role="switch">
            </div>
          </div>
        </div>
        <label for="autoscroll-switch"><span class="mdc-typography--subtitle2 omnicolor">Log Auto Scroll</span></label>
      </div>
      <a class="mdc-list-item mdc-list-item--activated" href="#" aria-selected="true">
        <i class="material-icons mdc-list-item__graphic" aria-hidden="true">inbox</i>
        <span class="mdc-list-item__text">Inbox</span>
      </a>
      <a class="mdc-list-item" href="#">
        <i class="material-icons mdc-list-item__graphic" aria-hidden="true">send</i>
        <span class="mdc-list-item__text">Outgoing</span>
      </a>
      <a class="mdc-list-item" href="#">
        <i class="material-icons mdc-list-item__graphic" aria-hidden="true">drafts</i>
        <span class="mdc-list-item__text">Drafts</span>
      </a>
    </nav>
  </div>
</aside>
<div class="mdc-drawer-scrim"></div>
<button class="mdc-button">Open</button>

CODEPEN


Solution

  • Problem

    The MDC Navigation Drawer is not really designed to be placed on the right side. Here's the quote from this link discussing this specific issue:

    We've checked with our designers and this behavior isn't intended to be supported for navigation drawer specifically, but there are plans for more flexible components to accomplish this in the future.

    I can see that because of this, you used a workaround to place the navigation drawer to the right. That workaround involves using dir="rtl". Then, you wanted to invert the direction of the MDC Switch using dir="ltr" on one of the ancestor elements. However, according to the docs, in complex layouts ("complex" not specified), doing the above doesn't always work all the time. I tried doing that and it didn't work.


    Explanation

    When the MDN Switch detects that its ancestor has the attribute [dir="rtl"], it modifies two CSS properties: right and transform: translateX(...) (when checked). What can we do? We can alter those CSS properties back to when the switch does not have said modifiers. Doing this, the MDN Switch will correctly switch on from left to right and off from right to left.


    Solution

    To do this, we can easily add another class mdn-switch--ltr to the container of the MDN Switch. The CSS properties that caused the MDN Switch to move in the opposite direction and start from the right are transform: translate(-20px) and right: 18px respectively. Overriding (either using a higher specificity or the keyword !important) these to the ltr values of transform: translate(20px) and right: 0px solves the problem.

    Here's a working example (using a higher specificity). Do try running it.

    window.mdc.autoInit();
    var drawer = mdc.drawer.MDCDrawer.attachTo(document.querySelector('.mdc-drawer'));
    
    var button = document.querySelector('button');
    mdc.ripple.MDCRipple.attachTo(button);
    button.addEventListener('click', function() {
      drawer.open = true;
    });
    [dir="rtl"] .mdc-switch--ltr .mdc-switch__thumb-underlay  {
      right: 0;
    }
    
    [dir="rtl"] .mdc-switch--ltr.mdc-switch--checked .mdc-switch__thumb-underlay {
      transform: translateX(20px);
    }
    <script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.js"></script>
    <link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.css" rel="stylesheet"/>
    <aside class="mdc-drawer mdc-drawer--modal" dir="rtl">
      <div class="mdc-drawer__content">
        <nav class="mdc-list">
          <div class="mdc-form-field">
          
          
            <div class="mdc-switch mdc-switch--ltr" data-mdc-auto-init="MDCSwitch" id="mdcAutoScroll">
              <div class="mdc-switch__track"></div>
              <div class="mdc-switch__thumb-underlay">
                <div class="mdc-switch__thumb">
                  <input type="checkbox" id="autoscroll-switch" class="mdc-switch__native-control" role="switch">
                </div>
              </div>
            </div>
            
            
            <label for="autoscroll-switch">
              <span class="mdc-typography--subtitle2 omnicolor">Log Auto Scroll</span>
            </label>
          </div>
          <a class="mdc-list-item mdc-list-item--activated" href="#" aria-selected="true">
            <i class="material-icons mdc-list-item__graphic" aria-hidden="true">inbox</i>
            <span class="mdc-list-item__text">Inbox</span>
          </a>
          <a class="mdc-list-item" href="#">
            <i class="material-icons mdc-list-item__graphic" aria-hidden="true">send</i>
            <span class="mdc-list-item__text">Outgoing</span>
          </a>
          <a class="mdc-list-item" href="#">
            <i class="material-icons mdc-list-item__graphic" aria-hidden="true">drafts</i>
            <span class="mdc-list-item__text">Drafts</span>
          </a>
        </nav>
      </div>
    </aside>
    <div class="mdc-drawer-scrim"></div>
    <button class="mdc-button">Open</button>