Skip to content

Conversation

amyleadem
Copy link
Contributor

@amyleadem amyleadem commented Apr 10, 2023

Summary

Updated input mask functionality and attributes. This update simplifies the mask attribute requirements, provides instant feedback to the user if they enter an invalid character, and allows for better keyboard controls.

Some notes:

  • The original branch for this work (mm-input-mask) in PR USWDS input mask version 2 #5104 appears to have been corrupted and/or is missing commits. This PR attempts to fill in the gaps in history and resolve items that were identified in the comments of that PR.
  • I am proposing that this PR acts as an MVP and includes (at least) all possible breaking changes. There are some items that need more JavaScript work and I have outlined them in "Outstanding issues" below. I don't believe any of these would be breaking changes and I propose we open new issues for these items to keep things moving.

Breaking change

⚠️ This is a breaking change.

  1. The input must now include the usa-input-mask class. Before the class was named usa-masked.
  2. Required attributes have been updated. See "Component attribute updates" table below for details.
  3. The mask attribute requires different values than pattern and data-charset did before. See "Component attribute updates" table below for details.

Related issues

Closes #5054, closes #5227.

Documentation update issue: uswds/uswds-site#2062

Related pull requests

This work originates from PR #5104

Documentation update (WIP): uswds/uswds-site#2073

Preview link

Preview link: Input mask

Major changes

This is a significant rewrite that:

Improved end-user interaction

  • Added a screen reader-friendly hint message to notify the user when they enter an invalid character type
  • Automatically advance cursor past mask punctuation
  • Prevent flashing disallowed character input
  • Allow common arrow cursor interactions (up: move to end, down: move to front, etc)
  • Allow leading mask punctuation (like ( in phone numbers)
  • Better handle pasted content
  • Better handle multi-key combination input (shift-, option-, etc key combinations)

Enhanced input mask creation attributes

  • Simplified the method for adding a mask pattern
    • Replaced the regex-based pattern and data-charset attributes with the mask attribute, which accepts the letter A to represent any alphabetic character, the number 9 to represent any numeric character, and format characters like - and /
  • New invalid character hint message can be customized with data attributes
    • Users can now customize status message text with new data-invalid-alpha-text and data-invalid-numeric-text attributes
  • Added ability to auto-format casing with forced-case attributes
    • Added new forceupper and forcelower attributes

Improved developer experience

  • Added unit tests
  • Added JSDocs comments to each function

Component attribute updates

Attribute name Previous name Required? Description
.usa-input-mask .usa-masked Yes Triggers component initialization and adds styles
data‑invalid‑alpha‑text -- No Overrides the default value for the invalid alphabetic character hint text. Default value: Please enter a letter character here
data‑invalid‑numeric‑text -- No Overrides the default value for the invalid number character hint text. Default value: Please enter a number character here
forcelower -- No Forces casing on alphabetic characters. Add forcelower="true" to the input element to enforce lowercase letters.
forceupper -- No Forces casing on alphabetic characters. Add forceupper="true" to the input element to enforce uppercase letters.
inputmode inputmode No Tells browsers which keyboard type to display. For masks that contain all numbers, set inputmode to numeric to display a numeric keyboard. Set inputmode to tel to display a telephone keyboard. Set inputmode to text if your input mask includes alphabetic characters.
mask data‑charset, pattern Yes Defines the format of your mask. Use the number 9 to represent any number, the letter A to represent any letter, and any format character needed in your mask. For example, an input that requires three numbers followed by four letters with a hyphen in-between would have a mask attribute that looks like 999-AAAA.
placeholder placeholder Yes Creates the visual placeholder and informs some elements of mask formatting. Use underscores _ for character input placeholders combined with any valid format characters to customize your input mask. For example, a U.S. telephone placeholder attribute may look like (___) ___-____.

Problem statement

  1. The input mask component does not provide any feedback when an invalid character is entered.
  2. Keyboard interactions result in unpredictable outcomes
  3. Setting up the input mask component pattern can seem complicated
  4. Using format characters can cause unpredictable outcomes

Comment from PR #5104:

Here are some of the details on why a rewrite was initiated:

  • error/invalid character handling
    • the new mask gives instant feedback for invalid characters, similar to how the character counter behaves
    • btw I saw the issues you found with spaces which I will address first
  • weirdness with the current mask https://designsystem.digital.gov/components/input-mask/
    • when you type an invalid character, it shows the character for a split second and then disappears (screen readers call it out as well, this was perhaps the biggest issue)
    • with the current mask, there is some weirdness in a field with format characters (like telephone)... move to the right of a format character and try to use the arrow keys
    • you can't highlight all and delete on some masks (like telephone)
    • you can't use a leading format character
      • so with the current mask, you can't have () - we were forced to go with --__

Solution

Tasks completed since #5104

  • Add forceupper and forcelower attribute controls to storybook (53a0b8a)
  • Remove default status message (5f55796)
  • Remove usa-input-mask__field markup requirement
    • Moved usa-input-mask from container element to the input itself. This replaced the need for .usa-input-mask__field. (9a49a4e)
  • Dynamically associate aria-describedbywith SR status message element
  • Removed the need for empty status markup at init
    • Dynamically generates the status message element instead (5f55796)
  • Align use of usa-form and usa-form-group with other form components
    • Originated from this comment: USWDS input mask version 2 #5104 (comment)
    • Moved usa-input-mask from a container element to the input element itself. This means that usa-form and usa-form-group are no longer contained inside usa-input-mask. (9a49a4e)
  • Align error message styling with other components
    • Replaced custom error text styles with usa-error-message class (a16a662)
  • Add data attributes to customize status message languages (2b4e778)
  • Assess status message language (Should we find a less passive alternative?)
    • Changed "A number character is required here" to "Please enter a number here" (Thanks @bonnieAcameron @sarah-sch for the assist)
  • Remove date story
    • Removed date story because input mask cannot successfully validate dates (Example: it is possible to submit 99/99/9999 without error) (1e70efa)
  • Fix - cannot tab to next item (aa27c1f)
    • We should confirm that this fix doesn't break anything.
  • Checks for required attributes:mask, placeholder (ede9b6f)
  • Trigger invalid input hint with each invalid character, instead of just the first
    • We should add a default status so that screen reader reads out more consistently
    • Depending on the content of the default status, we might want to consider removing the aria-describedby connection done in 8f4f646
  • In numeric masks, special characters are not identified as invalid
    • The following characters do not trigger the invalid character warning AND appear in the numeric mask: ! # ^ &
    • The following characters do not trigger the invalid character warning and do NOT appear in the numeric mask: @ $ % * ( ) -
      • Note: these are included in FORMAT_CHARACTERS
  • In alphanumeric masks, special characters can trigger the incorrect invalid warning
    • For example, in the alphanumeric example, typing @ into the first position triggers a "Please enter a valid number character here", but the pattern is expecting a letter.
  • Pasting in content with invalid characters does nothing and provides no feedback. Example: pasting "145-62-0495" into the alphanumeric example
  • Pasting in partial content with valid characters does nothing and provides no feedback. For example in the alphanumeric example, type the letter A into the first position, then try copying the string BC1234 or BC-1234 to finish it out.
  • Multi-selection then change/delete does not work. Multi-selection then delete deletes the character before the selection not the selected text. Note that select-all then delete does work as expected.
  • Cut/ctrl + x or ctrl + backspace removes chunk of placeholder
  • Add clarity to hint examples
  • Update unit tests
  • Make code more readable/Add JS comments

Open discussion items

From @thisisdano in #5227 (comment)):

  • Should there be a "Please enter a valid character" message pre-populating the status field?
    • Dan: I'm inclined to say that this should be blank.
    • Amy: I removed this, but realized that the default message was preserving the vertical space. Now the content below will get bumped down if an invalid character is entered.
  • Disallowed character status updates announce only once in VO. Should they run after each input of a disallowed character?
    • Dan: I think yes
    • Amy: At least in voiceover, it would help to have a hint message that serves as the screen reader default status so that the message element isn't empty after invalid selection.
  • Should there be a status update for trying to enter more characters than the mask supports (i.e. every time you try to enter a character beyond the mask limit)?
    • Dan: I think yes
    • Amy: I have added this to "Outstanding items"
  • And a big one: Should input mask be a separate "component" or a data-element driven enhancement on the standard text input? Or something else?
    • Amy: TBD - we can discuss in the comments and at dev sync if not resolved before that

Other questions :

  • I removed the date example story because it wasn't able to mask all invalid characters (example: 99/99/9999 is a valid date). Did we want to keep the date story as is, improve it so it has limitations on which numbers are expected in each field, or just rely on the date picker component to do this?
  • Are there any other breaking changes we want to include? Is this the ideal structure?

Outstanding items

Proposing we open new issues for these

Testing and review

Confirm that the component meets functionality requirements as defined in the Input Mask requirements document (Google docs) 🔒

@amyleadem amyleadem added this to the uswds 3.6.0 milestone Jul 20, 2023
@mejiaj mejiaj modified the milestones: uswds 3.7.0, uswds 3.8.0 Nov 16, 2023
@thisisdano thisisdano modified the milestones: uswds 3.8.0, uswds 3.9.0 Mar 11, 2024
@juliasolorzano juliasolorzano removed their request for review March 26, 2025 14:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

USWDS - Input Mask refactor
5 participants