---
title: Input mask (Vanilla) - USWDS + Tailwind
description: Guide people toward a valid format as they type with an input mask
  for constrained text fields.
---

# Input mask

Guide people toward a valid format as they type with an input mask for constrained text fields.

## Example

```html
<div class="space-y-12">
  <div class="max-w-xs" data-scope="input-mask" data-part="root" id="mask-ssn">
    <label for="input-mask:mask-ssn:input" class="block">Social Security Number</label>
    <div id="hint-ssn" class="text-gray-50">For example, 123 45 6789</div>
    <div class="relative mt-2">
      <div aria-hidden="true" class="absolute inset-0 p-2 pointer-events-none border inline-flex whitespace-pre">
        <span data-scope="input-mask" data-part="content" class="text-gray-50 [&>i]:invisible [&>i]:not-italic"></span>
      </div>
      <input id="input-mask:mask-ssn:input" data-scope="input-mask" data-part="input" inputmode="numeric" autocomplete="off" placeholder="___ __ ____" aria-describedby="hint-ssn" class="p-2 w-full h-10 border border-gray-60 focus:outline-offset-0 focus:outline-4 focus:outline-blue-40v placeholder:invisible" />
    </div>
  </div>

  <div class="max-w-xs" data-scope="input-mask" data-part="root" id="mask-phone">
    <label for="input-mask:mask-phone:input" class="block">US Telephone Number</label>
    <div id="hint-phone" class="text-gray-50">For example, 123-456-7890</div>
    <div class="relative mt-2">
      <div aria-hidden="true" class="absolute inset-0 p-2 pointer-events-none border inline-flex whitespace-pre">
        <span data-scope="input-mask" data-part="content" class="text-gray-50 [&>i]:invisible [&>i]:not-italic"></span>
      </div>
      <input id="input-mask:mask-phone:input" data-scope="input-mask" data-part="input" inputmode="tel" autocomplete="tel" placeholder="___-___-____" aria-describedby="hint-phone" class="p-2 w-full h-10 border border-gray-60 focus:outline-offset-0 focus:outline-4 focus:outline-blue-40v placeholder:invisible" />
    </div>
  </div>

  <div class="max-w-xs" data-scope="input-mask" data-part="root" id="mask-zip">
    <label for="input-mask:mask-zip:input" class="block">ZIP Code</label>
    <div id="hint-zip" class="text-gray-50">For example, 12345-6789</div>
    <div class="relative mt-2">
      <div aria-hidden="true" class="absolute inset-0 p-2 pointer-events-none border inline-flex whitespace-pre">
        <span data-scope="input-mask" data-part="content" class="text-gray-50 [&>i]:invisible [&>i]:not-italic"></span>
      </div>
      <input id="input-mask:mask-zip:input" data-scope="input-mask" data-part="input" inputmode="numeric" autocomplete="postal-code" placeholder="_____-____" aria-describedby="hint-zip" class="p-2 w-full h-10 border border-gray-60 focus:outline-offset-0 focus:outline-4 focus:outline-blue-40v placeholder:invisible" />
    </div>
  </div>

  <div class="max-w-xs" data-scope="input-mask" data-part="root" id="mask-alpha">
    <label for="input-mask:mask-alpha:input" class="block">Alphanumeric</label>
    <div id="hint-alpha" class="text-gray-50">For example, A1B 2C3</div>
    <div class="relative mt-2">
      <div aria-hidden="true" class="absolute inset-0 p-2 pointer-events-none border inline-flex whitespace-pre">
        <span data-scope="input-mask" data-part="content" class="text-gray-50 [&>i]:invisible [&>i]:not-italic"></span>
      </div>
      <input id="input-mask:mask-alpha:input" data-scope="input-mask" data-part="input" data-charset="A#A #A#" autocomplete="off" placeholder="___ ___" aria-describedby="hint-alpha" class="p-2 w-full h-10 border border-gray-60 focus:outline-offset-0 focus:outline-4 focus:outline-blue-40v placeholder:invisible" />
    </div>
  </div>
</div>
```

## Component API

### Initialization

Run after the component markup exists:

```js
import { inputMaskInit } from '@uswds-tailwind/compat/input-mask'

inputMaskInit()
```

### Anatomy

Set authored attributes in your HTML. The component manages generated attributes. Types describe HTML attribute values.

#### `root`

Wraps the input and mask overlay.

| Attribute | Type | Description |
| - | - | - |
| `data-scope` | `"input-mask"` | **Authored.** Identifies the component scope. |
| `data-part` | `"root"` | **Authored.** Identifies this part. |

#### `input`

Required native input.

| Attribute | Type | Description |
| - | - | - |
| `data-part` | `"input"` | **Authored.** Identifies this part. |
| `placeholder` | `string` | **Authored.** Mask format, such as `___-___-____`. The `mask` option takes precedence. |
| `data-charset` | `string` | **Authored.** Character rules, such as `A#A #A#`: `A` accepts a letter and `#` a digit. The `charset` option takes precedence. |
| `value` | `string` | **Authored.** Initial value; the `defaultValue` option takes precedence. |
| `pattern` | `string` | **Authored.** Native browser validation pattern; does not configure the mask. |
| `maxlength` | `integer` | **Generated.** Derived from the mask. |
| `data-placeholder` | `string` | **Generated.** Derived from the mask; the native `placeholder` is removed. |
| `id` | `string` | **Generated.** Defaults to `input-mask:<root-id>:input`; use `ids.input` to override. |

#### `content`

Required overlay. The runtime generates children for entered text and the remaining mask. Style the generated `i` with `visibility: hidden` and normal font style to reserve space for entered text.

| Attribute | Type | Description |
| - | - | - |
| `data-part` | `"content"` | **Authored.** Identifies this part. |

### Configuration

Pass these JavaScript options to the instance constructor or factory. Authored configuration attributes are read during construction.

| Option | Description |
| - | - |
| `mask` | `string`. Mask format; overrides the input placeholder. |
| `charset` | `string`. Character rules; overrides `data-charset`. |
| `defaultValue` | `string`. Initial value; overrides the input value. |
| `value` | `string`. Controlled value; takes precedence over the default. |
| `ids.input` | Custom input ID for label composition. |

### Methods

| Method | Returns | Description |
| - | - | - |
| `api.setValue(value)` | `void` | Requests a formatted value update. |
| `destroy()` | `void` | Stops the instance; does not restore original markup. |

```js
import { InputMask } from '@uswds-tailwind/compat/input-mask'

const mask = InputMask.getOrCreateInstance(
  '[data-scope="input-mask"][data-part="root"]',
)

mask.api.setValue('2025550123')
```

See [initialization and cleanup](https://uswds-tailwind.com/docs/vanilla/javascript#instance-lifecycle).

### Callbacks

| Callback | Payload | When it runs |
| - | - | - |
| `onValueChange` | `{ value: string }` | The formatted value changes or a controlled change is requested. |

Pass callbacks in instance options. These are JavaScript functions, not emitted DOM events.

### Behavior

Uncontrolled typing formats on `keyup`. Controlled typing proposes formatted changes on `input`. The mask does not infer invalid state from partial input; native `pattern` and form attributes determine validity.

### Accessibility

* Link the label to the generated input ID, or supply `ids.input`.
* Keep a visible format hint and connect it with `aria-describedby`.
* For a controlled value, your application must supply updates after change callbacks. See [shared lifecycle](https://uswds-tailwind.com/docs/vanilla/javascript#instance-lifecycle).
