<input type="tel">

Baseline 已广泛支持

此特性已相当成熟,可在许多设备和浏览器版本上使用。自 ⁨2015 年 7 月⁩以来,各浏览器均已提供此特性。

类型为 tel<input> 元素用于让用户输入和编辑电话号码。与 <input type="email"><input type="url"> 不同,输入的值在表单提交前不会自动验证为特定格式,因为世界各地的电话号码格式差异很大。

试一试

<label for="phone">
  Enter your phone number:<br />
  <small>Format: 123-456-7890</small>
</label>

<input
  type="tel"
  id="phone"
  name="phone"
  pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
  required />
label {
  display: block;
  font:
    1rem "Fira Sans",
    sans-serif;
}

input,
label {
  margin: 0.4rem 0;
}

尽管 tel 类型的输入框在功能上与标准的 text 输入框相同,但它们确实有其用处;其中最明显的一点是,移动浏览器——尤其是手机上的浏览器——可能会选择性地呈现一个为输入电话号码而优化的自定义键盘。为电话号码使用特定的输入类型也使得添加自定义验证和处理电话号码更为方便。

备注: 不支持 tel 类型的浏览器会回退为标准的 text 输入框。

<input> 元素的 value 属性包含一个字符串,该字符串表示一个电话号码或者是一个空字符串 ("")。

附加属性

除了全局属性以及适用于所有 <input> 元素的属性(无论其类型如何)之外,电话号码输入框还支持以下属性。

list

列表属性的值是位于同一文档中的 <datalist> 元素的 id<datalist> 为此输入提供了一个预定义值列表,以供用户建议。列表中与 type 不兼容的任何值都不会包含在建议选项中。提供的值是建议,而不是要求:用户可以从这个预定义列表中选择,也可以提供不同的值。

maxlength

用户可以在电话号码字段中输入的最大字符串长度(以 UTF-16 代码单元为单位)。这必须是一个 0 或更高的整数值。如果没有指定 maxlength,或者指定了一个无效值,则电话号码字段没有最大长度。该值也必须大于或等于 minlength 的值。

如果字段中输入的文本长度大于 maxlength UTF-16 代码单元,则输入将无法通过 约束验证。约束验证仅在用户更改值时应用。

minlength

用户可以在电话号码字段中输入的最小字符串长度(以 UTF-16 代码单元为单位)。这必须是一个非负整数值,且小于或等于 maxlength 指定的值。如果没有指定 minlength,或者指定了一个无效值,则电话号码输入框没有最小长度。

如果输入到字段中的文本长度小于 minlengthUTF-16 代码单元,则电话号码字段将无法通过约束验证。约束验证仅在用户更改值时应用。

pattern

当指定 pattern 属性时,它是一个正则表达式,输入框的 value 必须与该正则表达式匹配才能通过 约束验证。它必须是有效的 JavaScript 正则表达式,如 RegExp 类型所使用,并记录在我们的正则表达式指南中;在编译正则表达式时指定 'u' 标志,以便将模式视为 Unicode 码点序列,而不是 ASCII。模式文本周围不应指定正斜杠。

如果未指定或指定的模式无效,则不应用正则表达式,并且此属性将完全被忽略。

注意: 使用 title 属性来指定大多数浏览器将作为工具提示显示的文本,以解释匹配模式的要求。您还应该在附近包含其他解释性文本。

有关详细信息和示例,请参见下文的模式验证

placeholder

placeholder 属性是一个字符串,它向用户提供一个简短的提示,说明字段中预期哪种信息。它应该是一个词或短语,演示预期的数据类型,而不是解释性消息。文本不能包含回车或换行符。

如果控件的内容具有单一方向性(从左到右从右到左),但需要以相反的方向性呈现占位符,您可以使用 Unicode 双向算法格式字符来覆盖占位符内的方向性;有关更多信息,请参阅如何使用 Unicode 控件处理双向文本

注意: 如果可以,请避免使用 placeholder 属性。它不如其他解释表单的方式在语义上有用,并且可能导致您的内容出现意外的技术问题。有关更多信息,请参阅<input> 标签

readonly

一个布尔属性,如果存在,则表示该字段不能由用户编辑。但是,其 value 仍然可以通过 JavaScript 代码直接设置 HTMLInputElement value 属性来更改。

注意: 由于只读字段不能有值,因此 required 对同时指定了 readonly 属性的输入没有影响。

size

size 属性是一个数字值,表示输入字段应该有多宽(以字符为单位)。该值必须是一个大于零的数字,默认值为 20。由于字符宽度不同,这可能不完全精确,不应依赖于此;最终的输入可能比指定的字符数更窄或更宽,具体取决于字符和正在使用的字体(font 设置)。

限制用户可以在字段中输入的字符数。它只指定一次大约可以看到多少个字符。要对输入数据的长度设置上限,请使用maxlength 属性。

使用 tel 输入框

电话号码是 Web 上非常普遍收集的一种数据类型。例如,在创建任何类型的注册或电子商务网站时,你很可能需要询问用户的电话号码,无论是出于业务目的还是紧急联系目的。鉴于电话号码的输入如此普遍,不幸的是,“一刀切”的电话号码验证解决方案并不可行。

幸运的是,你可以根据自己网站的需求,自行实现适当级别的验证。详情请参见下文的验证

自定义键盘

<input type="tel"> 的一个主要优点是它能让移动浏览器显示一个专门用于输入电话号码的键盘。例如,以下是一些设备上键盘的样子。

适用于 Android 的 Firefox WebKit iOS (Safari/Chrome/Firefox)
Firefox for Android screen shot Firefox for iOS screenshot

一个基本的 tel 输入框

在其最基本的形式中,tel 输入框可以像这样实现

html
<label for="telNo">Phone number:</label>
<input id="telNo" name="telNo" type="tel" />

这里并没有什么神奇之处。当提交到服务器时,上述输入框的数据将表示为,例如,telNo=+12125553151

占位符

有时候,提供一个上下文提示来说明输入数据应采用何种格式是很有帮助的。如果页面设计没有为每个 <input> 提供描述性标签,这一点尤其重要。这就是占位符的作用所在。占位符是一个展示 value 应采用格式的值,它通过呈现一个有效值的示例,在元素的 value"" 时显示在编辑框内。一旦数据输入到框中,占位符就会消失;如果清空输入框,占位符会重新出现。

这里,我们有一个带有占位符 123-4567-8901tel 输入框。请注意当你操作编辑字段内容时,占位符是如何消失和重现的。

html
<input id="telNo" name="telNo" type="tel" placeholder="123-4567-8901" />

控制输入大小

你不仅可以控制输入框的物理长度,还可以控制输入文本本身允许的最小和最大长度。

物理输入元素大小

输入框的物理大小可以通过 size 属性来控制。通过它,你可以指定输入框一次可以显示的字符数。例如,在这个例子中,tel 编辑框有 20 个字符宽

html
<input id="telNo" name="telNo" type="tel" size="20" />

元素值长度

size 与输入电话号码的长度限制是分开的。你可以使用 minlength 属性指定输入电话号码的最小长度(以字符为单位);同样地,使用 maxlength 设置输入电话号码的最大长度。

下面的示例创建了一个 20 个字符宽的电话号码输入框,要求内容长度不短于 9 个字符,且不长于 14 个字符。

html
<input
  id="telNo"
  name="telNo"
  type="tel"
  size="20"
  minlength="9"
  maxlength="14" />

备注: 上述属性确实会影响验证——如果值的长度小于 9 个字符或超过 14 个字符,上述示例的输入框将被视为无效。大多数浏览器甚至不允许你输入超过最大长度的值。

提供默认选项

使用值属性提供单个默认值

一如既往,你可以通过设置其 value 属性为 tel 输入框提供一个默认值

html
<input id="telNo" name="telNo" type="tel" value="333-4444-4444" />

提供建议值

更进一步,你可以提供一个默认电话号码列表供用户选择。要做到这一点,请使用 list 属性。这并不会将用户限制在这些选项中,但可以让他们更快地选择常用的电话号码。这也为autocomplete提供了提示。list 属性指定了一个 <datalist> 元素的 ID,该元素反过来为每个建议值包含一个 <option> 元素;每个 optionvalue 是电话号码输入框对应的建议值。

html
<label for="telNo">Phone number: </label>
<input id="telNo" name="telNo" type="tel" list="defaultTels" />

<datalist id="defaultTels">
  <option value="111-1111-1111"></option>
  <option value="122-2222-2222"></option>
  <option value="333-3333-3333"></option>
  <option value="344-4444-4444"></option>
</datalist>

有了 <datalist> 元素及其 <option>s,浏览器会提供指定的值作为电话号码的可能值;这通常以包含建议的弹出菜单或下拉菜单的形式呈现。虽然具体的用户体验可能因浏览器而异,但通常点击编辑框会显示一个建议电话号码的下拉列表。然后,随着用户的输入,列表会调整以仅显示筛选后的匹配值。用户每输入一个字符都会缩小列表范围,直到用户做出选择或输入一个自定义值。

以下是它可能看起来像的截图

An input box has focus with a blue focus ring. The input has a drop-down menu showing four phone numbers the user can select.

验证

正如我们之前提到的,为电话号码提供一个“一刀切”的客户端验证解决方案是相当困难的。那么我们能做些什么呢?让我们考虑一些选项。

警告: HTML 表单验证不能替代服务器端脚本,后者确保输入的数据在被允许进入数据库之前格式正确。有人很容易就能对 HTML 进行调整,从而绕过验证,或者完全移除它。也有可能有人完全绕过你的 HTML,直接向你的服务器提交数据。如果你的服务器端代码未能验证它接收到的数据,当格式不正确的数据(或数据过大、类型错误等)被输入到你的数据库时,就可能引发灾难。

将电话号码设为必填项

你可以使用 required 属性,使得空输入无效并且不会提交到服务器。例如,让我们使用这个 HTML

html
<form>
  <div>
    <label for="telNo">Enter a telephone number (required): </label>
    <input id="telNo" name="telNo" type="tel" required />
    <span class="validity"></span>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

然后我们加入以下 CSS,用对勾标记有效条目,用叉号标记无效条目

css
div {
  margin-bottom: 10px;
  position: relative;
}

input[type="number"] {
  width: 100px;
}

input + span {
  padding-right: 30px;
}

input:invalid + span::after {
  position: absolute;
  content: "✖";
  padding-left: 5px;
  color: darkred;
}

input:valid + span::after {
  position: absolute;
  content: "✓";
  padding-left: 5px;
  color: #009000;
}

输出如下所示

模式验证

如果你想进一步限制输入的号码,使其必须符合特定的模式,你可以使用 pattern 属性,它的值是一个正则表达式,输入的值必须与之匹配。

在这个例子中,我们将使用与之前相同的 CSS,但我们的 HTML 改为如下所示

html
<form>
  <div>
    <label for="telNo">
      Enter a telephone number (in the form xxx-xxx-xxxx):
    </label>
    <input
      id="telNo"
      name="telNo"
      type="tel"
      required
      pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" />
    <span class="validity"></span>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

请注意,除非匹配 xxx-xxx-xxxx 模式,否则输入的值会被报告为无效;例如,41-323-421 将不被接受。800-MDN-ROCKS 也不会被接受。然而,865-555-6502 将被接受。这种特定的模式显然只适用于某些地区——在实际应用中,你可能需要根据用户的地区来改变使用的模式。

示例

在这个例子中,我们提供了一个 <select> 元素,让用户选择他们所在的国家,以及一组 <input type="tel"> 元素让他们输入电话号码的每个部分;完全可以有多个 tel 输入框。

每个输入框都有一个 placeholder 属性,向有视力的用户显示输入内容的提示;一个 pattern 属性,为所需部分强制执行特定数量的字符;以及一个 aria-label 属性,包含一个要为屏幕阅读器用户读出的提示,告诉他们该输入什么。

html
<form>
  <div>
    <label for="country">Choose your country:</label>
    <select id="country" name="country">
      <option>UK</option>
      <option selected>US</option>
      <option>Germany</option>
    </select>
  </div>
  <div>
    <p>Enter your telephone number:</p>
    <span class="areaDiv">
      <input
        id="areaNo"
        name="areaNo"
        type="tel"
        required
        placeholder="Area code"
        pattern="[0-9]{3}"
        aria-label="Area code" />
      <span class="validity"></span>
    </span>
    <span class="number1Div">
      <input
        id="number1"
        name="number1"
        type="tel"
        required
        placeholder="First part"
        pattern="[0-9]{3}"
        aria-label="First part of number" />
      <span class="validity"></span>
    </span>
    <span class="number2Div">
      <input
        id="number2"
        name="number2"
        type="tel"
        required
        placeholder="Second part"
        pattern="[0-9]{4}"
        aria-label="Second part of number" />
      <span class="validity"></span>
    </span>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

JavaScript 包含一个 onchange 事件处理器,当 <select> 的值改变时,它会更新 <input> 元素的 patternplaceholderaria-label,以适应那个国家/地区的电话号码格式。

js
const selectElem = document.querySelector("select");
const inputElems = document.querySelectorAll("input");

selectElem.onchange = () => {
  for (const e of inputElems) {
    e.value = "";
  }

  if (selectElem.value === "US") {
    inputElems[2].parentNode.style.display = "inline";

    inputElems[0].placeholder = "Area code";
    inputElems[0].pattern = "[0-9]{3}";

    inputElems[1].placeholder = "First part";
    inputElems[1].pattern = "[0-9]{3}";
    inputElems[1].setAttribute("aria-label", "First part of number");

    inputElems[2].placeholder = "Second part";
    inputElems[2].pattern = "[0-9]{4}";
    inputElems[2].setAttribute("aria-label", "Second part of number");
  } else if (selectElem.value === "UK") {
    inputElems[2].parentNode.style.display = "none";

    inputElems[0].placeholder = "Area code";
    inputElems[0].pattern = "[0-9]{3,6}";

    inputElems[1].placeholder = "Local number";
    inputElems[1].pattern = "[0-9]{4,8}";
    inputElems[1].setAttribute("aria-label", "Local number");
  } else if (selectElem.value === "Germany") {
    inputElems[2].parentNode.style.display = "inline";

    inputElems[0].placeholder = "Area code";
    inputElems[0].pattern = "[0-9]{3,5}";

    inputElems[1].placeholder = "First part";
    inputElems[1].pattern = "[0-9]{2,4}";
    inputElems[1].setAttribute("aria-label", "First part of number");

    inputElems[2].placeholder = "Second part";
    inputElems[2].pattern = "[0-9]{4}";
    inputElems[2].setAttribute("aria-label", "Second part of number");
  }
};

这个例子看起来是这样的

这是一个有趣的想法,展示了处理国际电话号码问题的一个潜在解决方案。当然,你必须扩展这个例子,为可能每一个国家提供正确的模式,这将是一项大量的工作,而且仍然不能完全保证用户会正确输入他们的号码。

这让你思考,是否值得在客户端花费这么多功夫,而你可以让用户在客户端以任何他们想要的格式输入他们的号码,然后在服务器上进行验证和清理。但这个选择由你来做。

技术摘要

一个表示电话号码的字符串,或为空
事件 changeinput
支持的常见属性 autocompletelistmaxlengthminlengthpatternplaceholderreadonlysize
IDL 属性 listselectionStartselectionEndselectionDirectionvalue
DOM 接口 HTMLInputElement
方法 select()setRangeText()setSelectionRange()
隐式 ARIA 角色 list 属性:textbox 带有 list 属性:combobox

规范

规范
HTML
# telephone-state-(type=tel)

浏览器兼容性

另见