Password input is a UI element designed to securely and confidentially capture a user’s password.

On this page


Component design version:

  • Password input v1.3.0

Note

You can find here the OUDS password input design guidelines.

Overview

Password input is a UI element designed to securely and confidentially capture a user’s password.

Password input feature enhances privacy by replacing characters with dots as they are typed. It also includes usability features like the option to show or hide the password and helper text to assist with password creation.

A password input is a specific configuration of the text input. It uses a .text-input wrapper to create a textual form field with OUDS styles, then wraps a pair of <input class="text-input-field"> and <label> elements in .text-input-container. Note that the <label> must come before the <input>.

A placeholder attribute is required on each <input> as our CSS-only floating label implementation relies on the :placeholder-shown pseudo-element to detect when the input is empty.

Note

Even if you don't need a placeholder, you must always define the placeholder attribute with a single space character. This ensures the label behaves correctly by preventing it from overlapping the input text when a value is entered.

Note

All other available features of the text input component can be used with the password input, such as leading icons, helper text, and validation states. Please refer to the text input documentation for more details.

You will need to write some additional JavaScript code to make the show/hide password button work properly: change the icon and the input type to display the password. You can find a live example with JavaScript below.

Enter a password with at least 8 characters (without the DEV- prefix).

Enter a password with at least 8 characters

Enter a password with at least 8 characters

Enter a password with at least 8 characters (without the DEV- prefix).

Password must be at least 8 characters (without the DEV- prefix).

Enter a password with at least 8 characters (without the DEV- prefix).

Password must be at least 8 characters (without the DEV- prefix).

Password is required.

Password is required.

<div class="text-input mb-medium">
  <div class="text-input-container">
    <label for="inputPassword">Password</label>
    <input type="password" id="inputPassword" class="text-input-field" placeholder=" ">
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
</div>
<div class="text-input mb-medium">
  <div class="text-input-container">
    <svg aria-hidden="true">
      <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#lock-closed"/>
    </svg>
    <label for="inputPasswordIcon">Password</label>
    <input type="password" id="inputPasswordIcon" class="text-input-field" placeholder="Minimum 8 characters">
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
</div>
<div class="text-input mb-medium">
  <div class="text-input-container">
    <svg aria-hidden="true">
      <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#lock-closed"/>
    </svg>
    <label for="inputPasswordPrefix">Password</label>
    <div class="input-container" data-bs-prefix="DEV-">
      <input type="password" id="inputPasswordPrefix" aria-describedby="inputPasswordPrefixHelper" class="text-input-field" placeholder=" ">
    </div>
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
  <p id="inputPasswordPrefixHelper" class="helper-text">Enter a password with at least 8 characters (without the DEV- prefix).</p>
</div>
<div class="text-input mb-medium">
  <div class="text-input-container text-input-container-outlined">
    <svg aria-hidden="true">
      <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#lock-closed"/>
    </svg>
    <label for="inputPasswordOutlined">Password</label>
    <input type="password" id="inputPasswordOutlined" aria-describedby="inputPasswordOutlinedHelper" class="text-input-field" placeholder=" ">
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
  <p id="inputPasswordOutlinedHelper" class="helper-text">Enter a password with at least 8 characters</p>
</div>
 <div class="text-input mb-medium">
  <div class="text-input-container text-input-container-outlined">
    <svg aria-hidden="true">
      <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#lock-closed"/>
    </svg>
    <label for="inputPasswordOutlinedValue">Password</label>
    <input type="password" id="inputPasswordOutlinedValue" aria-describedby="inputPasswordOutlinedValueHelper" class="text-input-field" placeholder=" " value="My$ecureP@ssw0rd">
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
  <p id="inputPasswordOutlinedValueHelper" class="helper-text">Enter a password with at least 8 characters</p>
</div>
<div class="text-input mb-medium">
  <div class="text-input-container">
    <label for="inputPasswordInvalid">Password</label>
    <div class="input-container" data-bs-prefix="DEV-">
      <input type="password" id="inputPasswordInvalid" class="text-input-field" aria-invalid="true" aria-describedby="inputPasswordInvalidError" placeholder=" " value="12345">
    </div>
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
  <p id="inputPasswordInvalidHelper" class="helper-text">Enter a password with at least 8 characters (without the DEV- prefix).</p>
  <p id="inputPasswordInvalidError" class="error-text">Password must be at least 8 characters (without the DEV- prefix).</p>
</div>
<div class="text-input mb-medium">
  <div class="text-input-container text-input-container-outlined">
    <svg aria-hidden="true">
      <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#lock-closed"/>
    </svg>
    <label for="inputPasswordOutlinedInvalid">Password</label>
    <div class="input-container" data-bs-prefix="DEV-">
      <input type="password" id="inputPasswordOutlinedInvalid" class="text-input-field" aria-invalid="true" aria-describedby="inputPasswordOutlinedInvalidError" placeholder=" " value="12345">
    </div>
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
  <p id="inputPasswordOutlinedInvalidHelper" class="helper-text">Enter a password with at least 8 characters (without the DEV- prefix).</p>
  <p id="inputPasswordOutlinedInvalidError" class="error-text">Password must be at least 8 characters (without the DEV- prefix).</p>
</div>
<div class="text-input mb-medium">
  <div class="text-input-container">
    <label for="mandatoryPasswordNotEmpty" class="is-required">Password</label>
    <input type="password" id="mandatoryPasswordNotEmpty" class="text-input-field" placeholder=" " value="12345" required>
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
  <p id="mandatoryPasswordNotEmptyError" class="error-text">Password is required.</p>
</div>
<div class="text-input mb-medium">
  <div class="text-input-container">
    <label for="mandatoryPasswordError" class="is-required">Password</label>
    <input type="password" id="mandatoryPasswordError" class="text-input-field" placeholder=" " required aria-invalid="true" aria-describedby="mandatoryPasswordErrorText">
    <button class="btn btn-minimal btn-icon" aria-pressed="false" type="button">
      <svg aria-hidden="true">
        <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
      </svg>
      <span class="visually-hidden">Show password</span>
    </button>
  </div>
  <p id="mandatoryPasswordErrorText" class="error-text">Password is required.</p>
</div>
html

JavaScript

Live example

This example shows how to implement a 'Show password' button for a password input field. This is achieved by toggling four elements:

  • the input type, changing it from password to text
  • the aria-pressed state of the button
  • the button label
  • the button icon

The visually hidden label of the button should be changed from "Show password" to "Hide password" to indicate correctly the button's purpose. Please note that the button's aria-pressed state must be initialized. The JavaScript code provided below is an example and must be adapted for your project.

Heads up!

Security considerations

For security reasons, don't forget to reset the input type to password before form submission to prevent the password from being stored in the browser's autocomplete history.

<div id="liveShowPasswordExample" class="text-input component-max-width">
  <div class="text-input-container">
    <label for="liveInputPassword">Password</label>
    <input type="password" id="liveInputPassword" class="text-input-field" placeholder=" ">
      <button class="btn btn-minimal btn-icon" id="togglePassword" aria-pressed="false" type="button">
        <svg aria-hidden="true">
          <use xlink:href="/orange/docs/1.2/assets/img/ouds-web-sprite.svg#accessibility-vision"/>
        </svg>
        <span class="visually-hidden">Show password</span>
      </button>
  </div>
</div>
html
// Toggle password visibility
const togglePasswordButton = document.querySelector('#liveShowPasswordExample #togglePassword')
if (togglePasswordButton) {
  const passwordInput = document.querySelector('#liveShowPasswordExample #liveInputPassword')
  const iconUse = togglePasswordButton.querySelector('use')
  const buttonLabel = togglePasswordButton.querySelector('.visually-hidden')

  togglePasswordButton.addEventListener('click', event => {
    event.preventDefault()

    // Toggle the type attribute to make the password visible or hidden
    const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password'
    passwordInput.setAttribute('type', type)

    // Toggle the aria-pressed attribute, the button's label and the icon to reflect the change in state
    if (type === 'text') {
      togglePasswordButton.setAttribute('aria-pressed', 'true')
      buttonLabel.textContent = 'Hide password'
      iconUse.setAttribute('xlink:href', iconUse.getAttribute('xlink:href').replace('accessibility-vision', 'hide'))
    } else {
      togglePasswordButton.setAttribute('aria-pressed', 'false')
      buttonLabel.textContent = 'Show password'
      iconUse.setAttribute('xlink:href', iconUse.getAttribute('xlink:href').replace('hide', 'accessibility-vision'))
    }
  })
}