Discovering Google’s Material-Web: Crafting a Custom Password Field

Django Viewflow
4 min readAug 29, 2023

--

Introduction

In the rapidly evolving landscape of web development, utilizing pre-built component libraries has become a staple for building efficient and visually appealing applications. One such library that stands out is Google’s Material Web Components (MWC), often referred to as @material/web. MWC provides a suite of web components that align with Google's Material Design guidelines, now enhanced by the latest Material 3 features such as dynamic color and enhanced accessibility. These components are versatile, working seamlessly across various frameworks like Lit, React, Vue, and Svelte, as well as different web environments like Django and Wordpress.

But what if you want to build something that Material-Web doesn’t offer out-of-the-box? This article aims to guide you through the process of creating a custom password input field with toggle visibility using Material-Web components. We’ll also be leveraging the capabilities of Lit, a library that allows you to create standard custom elements with scoped styles and reactive properties.

Intro to Material Web Components https://github.com/material-components/material-web/blob/main/docs/intro.md
Intro to Material Web Components

To make it even more developer-friendly, we’ll be using Vite as our build tool, setting up a Lit-based TypeScript project to encapsulate all the magic. So, let’s delve in and craft our custom password field.

Setting Up the Project

First things first, let’s set up our project. Open up your terminal and run:

npm create vite@latest my-project -- --template lit-ts

This one-liner gets you a Lit and TypeScript enabled project. Once the command finishes, go into your new project folder and kickstart the development server:

cd my-project
npm install
npm run dev

You’ll find a sample Lit element in the src/my-element.ts file. That's our playground for the custom password field.

Adding Material-Web to Your Project

Next up, let’s get the Material-Web Components into our project. Install the library with:

npm install @material/web

For our custom password field, we’ll focus on two components: MdOutlinedTextField and MdIconButton. MdOutlinedTextField will serve as our password input field. We’ll place MdIconButton inside the text field to act as a password visibility toggle

Creating the Custom Password Field

Let’s start building our custom password field, step by step.

Extending MdOutlinedTextField

First off, VFPasswordField extends MdOutlinedTextField. We need to set some defaults like this.type="password"; and this.hasTrailingIcon = true; in the constructor. These lines set the initial state and tell the component to expect an icon inside it.

import { html, css } from 'lit'
import {customElement, query} from 'lit/decorators.js';
import {MdOutlinedTextField} from '@material/web/textfield/outlined-text-field';
import {MdIconButton} from '@material/web/iconbutton/icon-button';

@customElement('my-password-field')
export class MyPasswordField extends MdOutlinedTextField {
constructor() {
super();
this.type="password";
this.hasTrailingIcon = true;
//...
}
}

Using the @customElement decorator, we register our component as a custom HTML element in the browser.

Adding a Toggle Button

To actually insert the button, we override a private method called renderTrailingIcon from MdOutlinedTextField.

constructor() {
super();
this.type="password";
this.hasTrailingIcon = true;
(this as any).renderTrailingIcon = () => {
return html`
<span class="icon trailing" slot="end">
<md-icon-button toggle @change="${this.handleClick}">
<md-icon slot="selectedIcon">visibility_off</md-icon>
<md-icon>visibility</md-icon>
</md-icon-button>
</span>
`;
}
}

This gives us a toggle button within the password field — something not provided by the original MdOutlinedTextField.

Customizing styles

To finesse the appearance, we add some styles in the static styles section. Those styles would be incorporated into Shadow DOM, and would not have power outside our component.

@customElement('my-password-field')
class MyPasswordField extends MdOutlinedTextField {
static styles = [...MdOutlinedTextField.styles, css`
md-icon-button {
height: 26px;
padding-right: 8px;
min-inline-size: 16px;
}
`]
// ...
}

Here we extend MdOutlinedTextField.stylesand add own rule for our button inside

Handling Toggle Logic

Finally, let’s take care of the logic behind the toggle action. We use the @query decorator to get a reference to the md-icon-button element.

@query('md-icon-button')
button: MdIconButton | undefined;

With this reference, we implement the handleClick method to switch the input type between text and password.

handleClick() {
this.type = this.button?.selected ? "text" : "password";
}

This method changes the input type based on the button’s state, either revealing or hiding the password as the user chooses.

Finalizing the Build

After crafting our custom password field, there are a couple more steps to ensure everything works seamlessly.

We need to import and then export the relevant components. This ensures they are included in the final build.

import {MdIconButton} from '@material/web/iconbutton/icon-button';
import {MdIcon} from '@material/web/icon/icon';
export {
MyPasswordField,
MdIconButton,
MdIcon,
}

Loading Icon Fonts. To display icons, add the following line to your index.html:

<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined" rel="stylesheet" />

This will load the Material Symbols font, allowing the visibility icons in our custom password field to display correctly.

At the last step, add our own custom component to the html page

<body>
<my-password-field
label="Password"
supporting-text="password field demo">
</my-password-field>
</body>

Running the Project

if you haven’t already, launch the development server.

npm run dev

Your custom password field should now be accessible at http://localhost:5173 or a similar URL depending on your setup.

Password field demo

Conclusion

So there we have it — a custom Material password field crafted with care. We extended the functionality of Google’s Material-Web components, specifically MdOutlinedTextField, and slipped in a handy visibility toggle. While Material-Web is still in active development, it's already an incredibly useful tool. Its modular design not only allows for seamless integration but also provides a sturdy foundation to build self-contained, well-structured custom components. As the library matures, the potential for creating robust, user-friendly components only grows.

--

--

Django Viewflow
Django Viewflow

No responses yet