---
name: input-type
description: "Choosing HTML input attributes for web forms - type, inputmode, autocomplete, enterkeyhint, form wrapping - and the exact mobile keyboard each combination summons on iOS and Android. Use when writing or reviewing form fields, inputs, or any markup a phone keyboard will type into."
---

# input type — mobile keyboards for web forms

The exact mobile keyboard each HTML input configuration summons on iOS and
Android, with ready-to-use configurations and the documented traps. Generated
from the same dataset as https://inputtype.dev/ (updated 2026-07-24).

## Core rules

- Match the field's intent against the configurations below; when one fits,
  use its markup as-is.
- `type="number"` is only for genuine quantities. Identifiers made of
  digits — one-time codes, card numbers, phone numbers — are `type="text"`
  with `inputmode="numeric"`.
- Autofill and assist-bar offers (saved email, OTP from SMS, generated
  passwords, saved cards) need the field inside a `<form>`, served over
  HTTPS.
- Return-key labels (Search, Go, `enterkeyhint`) also need a `<form>` —
  outside one they silently fall back to plain Return.
- The keyboard is a hint, never validation: validate on the server no matter
  what `type` or `inputmode` say.
- In React, keyboard attributes are camelCased: `inputmode` → `inputMode`, `enterkeyhint` → `enterKeyHint`, `autocomplete` → `autoComplete`, `autocapitalize` → `autoCapitalize`, `autocorrect` → `autoCorrect`, `spellcheck` → `spellCheck`, `maxlength` → `maxLength`, `contenteditable` → `contentEditable`.

## Pick by intent

| Field | Configuration | Reference |
| --- | --- | --- |
| A card number, filled from the browser's saved cards — or scanned with the camera on iOS. | `type="text" inputmode="numeric" autocomplete="cc-number"` in a `<form>` | https://inputtype.dev/credit-card |
| A money amount with decimals — 19.99 — entered on a digit pad. | `type="text" inputmode="decimal"` | https://inputtype.dev/currency |
| An email address, typed without autocorrect surprises or filled from the browser's own suggestion. | `type="email" autocomplete="email"` in a `<form>` | https://inputtype.dev/email |
| A six-digit SMS code the user should never have to type by hand. | `type="text" inputmode="numeric" autocomplete="one-time-code"` in a `<form>` | https://inputtype.dev/otp |
| A password field that surfaces the saved credential — or generates a strong new one. | `type="password" autocomplete="current-password"` in a `<form>` | https://inputtype.dev/password |
| A phone number, typed on the dial pad or filled from the user's own contact card. | `type="tel" autocomplete="tel"` in a `<form>` | https://inputtype.dev/phone |
| A search box whose keyboard says Search on the return key. | `type="search"` in a `<form>` | https://inputtype.dev/search |

For anything not covered here — other layouts, enter keys, autofill tokens,
textareas, contenteditable — read [reference.md](reference.md) in this skill
directory.

## Configurations

### The right input for card numbers

A card number, filled from the browser's saved cards — or scanned with the camera on iOS.

```html
<form action="#">
  <input type="text" inputmode="numeric" autocomplete="cc-number" />
</form>
```

- **The keyboard is not validation.** Keyboard choice only shapes convenience. Paste, dictation, hardware keyboards, and autofill all bypass the layout, so the value still needs JS and server-side validation.

Details: https://inputtype.dev/credit-card · markdown mirror: https://inputtype.dev/credit-card.md

### The right input for currency amounts

A money amount with decimals — 19.99 — entered on a digit pad.

```html
<input type="text" inputmode="decimal" />
```

- **The decimal separator follows the device locale.** Accept both "." and "," when parsing and validating; never assume which separator key the user saw.
- **No minus key on iOS digit pads.** The iOS numeric and decimal pads have no minus key. Negative values need a different strategy: a full keyboard, a sign toggle in your UI, or a separate control.
- **type="number" is a trap.** For codes, PINs, and other digit strings use type="text" inputmode="numeric" pattern="[0-9]*" (the GOV.UK pattern). Reserve type="number" for true quantities where spinner stepping helps.

Details: https://inputtype.dev/currency · markdown mirror: https://inputtype.dev/currency.md

### The right input for email addresses

An email address, typed without autocorrect surprises or filled from the browser's own suggestion.

```html
<form action="#">
  <input type="email" autocomplete="email" />
</form>
```

Details: https://inputtype.dev/email · markdown mirror: https://inputtype.dev/email.md

### The right input for one-time codes

A six-digit SMS code the user should never have to type by hand.

```html
<form action="#">
  <input type="text" inputmode="numeric" autocomplete="one-time-code" />
</form>
```

- **OTP: one field, not six boxes.** Use ONE input with autocomplete="one-time-code" plus inputmode="numeric", not one box per digit.
- **OTP autofill degrades in iOS WebViews.** Inside iOS WebViews (in-app browsers), one-time-code suggestions can stop appearing after the first successful use.
- **The keyboard is not validation.** Keyboard choice only shapes convenience. Paste, dictation, hardware keyboards, and autofill all bypass the layout, so the value still needs JS and server-side validation.

Details: https://inputtype.dev/otp · markdown mirror: https://inputtype.dev/otp.md

### The right input for passwords

A password field that surfaces the saved credential — or generates a strong new one.

```html
<form action="#">
  <input type="password" autocomplete="current-password" />
</form>
```

Details: https://inputtype.dev/password · markdown mirror: https://inputtype.dev/password.md

### The right input for phone numbers

A phone number, typed on the dial pad or filled from the user's own contact card.

```html
<form action="#">
  <input type="tel" autocomplete="tel" />
</form>
```

- **The keyboard is not validation.** Keyboard choice only shapes convenience. Paste, dictation, hardware keyboards, and autofill all bypass the layout, so the value still needs JS and server-side validation.

Details: https://inputtype.dev/phone · markdown mirror: https://inputtype.dev/phone.md

### The right input for search fields

A search box whose keyboard says Search on the return key.

```html
<form action="#">
  <input type="search" />
</form>
```

Details: https://inputtype.dev/search · markdown mirror: https://inputtype.dev/search.md

## Traps

- **type="number" is a trap** (trap). For codes, PINs, and other digit strings use type="text" inputmode="numeric" pattern="[0-9]*" (the GOV.UK pattern). Reserve type="number" for true quantities where spinner stepping helps.
- **The decimal separator follows the device locale** (trap). Accept both "." and "," when parsing and validating; never assume which separator key the user saw.
- **OTP: one field, not six boxes** (trap). Use ONE input with autocomplete="one-time-code" plus inputmode="numeric", not one box per digit.
- **OTP autofill degrades in iOS WebViews** (quirk). Inside iOS WebViews (in-app browsers), one-time-code suggestions can stop appearing after the first successful use.
- **No minus key on iOS digit pads** (quirk). The iOS numeric and decimal pads have no minus key. Negative values need a different strategy: a full keyboard, a sign toggle in your UI, or a separate control.
- **Most enter-key labels only render inside a form** (quirk). Several enterkeyhint labels fall back to plain Return when the input is not inside a form. iOS also shows Go automatically for any input in a form with an action, even without enterkeyhint; Gboard support for "previous" is inconsistent.
- **In-app browsers diverge from Safari and Chrome** (note). Webviews inside apps like Instagram, TikTok, Facebook, and Gmail don't always match Safari/Chrome keyboard behavior — autofill offers in particular. On iOS, a web page also cannot hide the keyboard accessory bar in browser or PWA contexts.
- **The keyboard is not validation** (note). Keyboard choice only shapes convenience. Paste, dictation, hardware keyboards, and autofill all bypass the layout, so the value still needs JS and server-side validation.
- **When type and inputmode disagree, inputmode picks the keyboard** (note). inputmode controls which keyboard appears; type keeps its semantics. type="number" inputmode="decimal" summons the decimal pad while keeping number parsing and spinners; type="tel" inputmode="numeric" shows the plain digit pad instead of the phone pad.

## Scope and verification

This reference describes exactly:

- iOS: iOS 26 · Safari · stock iOS keyboard · en-US
- Android: Android 16 · Chrome · Gboard · en-US

Deliberately not covered:

- Samsung Keyboard (≈¼ of Android devices) — Gboard only
- In-app webview browsers (Instagram, TikTok, Facebook, Gmail) — Safari and Chrome only
- Locales beyond en-US, except explicitly documented locale traps
- date/time/color/file picker internals — pickers, not keyboards
- Hardware keyboards and iPad floating/split keyboards

No configuration carries a real-device verification stamp yet: every claim is simulated from documented platform behavior. Stamps land per configuration as the device pass completes.

## Source and install

Generated from the dataset behind https://inputtype.dev/ — the same source that
renders the site, the markdown mirrors (append `.md` to any recipe URL), and
https://inputtype.dev/llms.txt. Install or update (Claude Code):

```bash
mkdir -p ~/.claude/skills/input-type
curl -fsSL https://inputtype.dev/skill/SKILL.md -o ~/.claude/skills/input-type/SKILL.md
curl -fsSL https://inputtype.dev/skill/reference.md -o ~/.claude/skills/input-type/reference.md
```
