Toggle password

Web components may stand on their own, managing their logic and behavior, but I find them increasingly useful as a progressive enhancement for existing HTML elements. The idea is simple: you have standard nodes which implement a core, essential feature. Think of an input of type password to gather a precious, vital key. It may live in a form element or in a pointless example to showcase the widget, and achieves its one goal of receiving user input and hiding the text from unscrupulous eyes.

<input type="password" id="password" name="password" />

You have the node and wrap the input in a custom element. Through the custom element API you can then inspect the DOM and augment the unit. Wouldn’t it be nice, for instance, if there was a way to see just what was typed? Forgetful eyes may also like to see the actual value.

With little surprise, that is the exact premise of toggle-password, a recent component I wrote for a very serious project. Wrap the input element in the two-word helper.

<toggle-password>
  <input id="password" name="password" type="password" />
</toggle-password>

With JavaScript, with the necessary API, the script then ponders the input to add the following:

  • a button, a toggle to alternate between the legible and hidden text

  • a div, a plain wrapper to describe the change between the two modes

There is a good deal of consideration in the design of the component. The button, for instance, includes a label with the visually-hidden class. This one is not provided, but usually lives in the higher scope to hide content from sight, but not from assistive tech.

.visually-hidden:not(:focus):not(:active):not(:focus-within) {
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

The toggle includes two more icons to highlight the visibility of the password. Whenever you press the helper, the two are switched and so is the type of the input, between password and the more evident text.

The div carries the same visually-hidden utility, but also a role and aria-live attribute so that when the content changes it is spelled and made clear to screen readers.

You may want more freedom for the icons, for the words introducing the toggle or those spelling the sudden flip. For these issues you’ll have to modify the definition of the TogglePassword class directly — the script is quite understandable if you ever tipped your toe in JS.

Ultimately, however, you may care more about the style. This is where the custom element takes a very light and permissive approach: there is no assumption to what the button should look like. There is no CSS, no trace of a shadow DOM, and it is up to you to fill the gap.

You can target the nodes with global selectors, or be even more refined through the cascade.

toggle-password button {
  inline-size: 2em;
  block-size: 2em;
}

Here’s just a couple of things you’ll be glad to know. The first is the general structure of the final markup. The button pops up as a sibling of the input element, so you can position the two with flex, grid, or whichever layout system you may deem best.

<input id="password" name="password" type="password" />
<button aria-pressed="false">
  <!-- ... -->
</button>
<div class="visually-hidden" role="status" aria-live="polite"></div>

The button has also an aria-pressed attribute so you can tweak the style when the toggle is indeed pressed. The script takes care of alternating between the string values of "false" and "true".

toggle-password button[aria-pressed="true"] {
  color: tomato;
}

On top of this, the icons share a custom data-pressed attribute to match the values, the same binary state.

You get the point. You can focus on what matters. On the appearance of the larger component, on the purpose of the form, on the processing of user data. The custom element is just there as a small convenience to save you the hassle of creating a toggle yourself.