【ITニュース解説】How to Make Input Element with Text Type to Take the Number as Text Perfectly

2025年09月05日に「Dev.to」が公開したITニュース「How to Make Input Element with Text Type to Take the Number as Text Perfectly」について初心者にもわかりやすいように丁寧に解説しています。

作成日: 更新日:

ITニュース概要

HTMLの数字入力は`type="number"`や`type="text`+正規表現は課題。JavaScriptの`onkeydown`イベントにカスタム関数を設定し、数字と編集キーをリアルタイムで許可すれば、正確で快適な入力とする。

ITニュース解説

ウェブサイトでユーザーが情報を入力する際、HTMLのフォーム要素は非常に重要である。特に、クレジットカード番号や電話番号のように「数字だけ」を入力してほしい場面は頻繁にあるが、これを完璧に実現するのは意外と難しい。この記事では、HTMLが提供する標準的な入力フィールドの課題と、それらを解決するための洗練されたアプローチを解説する。

HTMLには、入力フィールドの種類を指定するためのtype属性が用意されている。例えば、type="text"はあらゆる文字を受け付ける一般的なテキスト入力欄であり、type="number"は数字の入力を想定して設計されている。しかし、これら標準のtype属性には、それぞれ一長一短があり、開発者はしばしば意図しない挙動に直面することになる。

まず、type="number"の問題点について見てみよう。数字専用の入力欄として理想的に思えるtype="number"だが、いくつかの課題がある。一つは、多くのデスクトップブラウザで、入力フィールドの横に数字を増減させるための上下のスピナーボタンが表示されてしまうことだ。これはウェブサイトのデザインやユーザーインターフェース(UI)の美しさを損ねる場合がある。また、minmax属性を設定しても、ユーザーは極端に長い数字(例えば、途方もなく大きな桁数の数字)を入力できてしまう。これは、入力する文字の「長さ」を制限するものではないため、例えば10桁の電話番号を入力してほしい場合でも、それ以上の桁数が入力できてしまう。さらに、ユーザーが数字以外の文字を含むテキストをコピーしてtype="number"のフィールドに貼り付けた場合、その時点では無効な入力が許されてしまい、フォームを送信するまで誤りに気づかないという問題もある。

次に、type="text"と正規表現(regex)を組み合わせるアプローチを考えてみよう。例えば、pattern="\d*"のように正規表現を設定すれば、数字のみを許可するように見える。しかし、この方法にも問題がある。ユーザーは正規表現で許可されていない文字(例えばアルファベット)を一時的に入力できてしまい、最終的な検証はフォーム送信時にしか行われない。また、最も厄介な問題として、pattern属性による制限は、バックスペースキーやデリートキー、さらにはペースト操作などの基本的な編集機能を阻害してしまうことがある。これはユーザー体験を著しく損ねる。さらに、モバイル環境では、type="text"を使うと数字入力に適したキーボードが自動的に表示されず、ユーザーが手動で切り替える手間が発生する場合もある。

これらの状況からわかるように、HTMLのrequiredminmaxpatternといった組み込みのバリデーション機能だけでは、完璧な入力制御を実現することは難しい。minmaxは数値の範囲を制限するが入力の長さを制限しないし、patternはフォーム送信時にしか本格的に機能しないため、リアルタイムでの入力制御には向いていない。

そこで登場するのが、JavaScriptを使ったカスタムソリューションだ。JavaScriptを使うことで、ユーザーのキー入力をリアルタイムで監視し、不適切な文字が入力される前にそれをブロックできる。これにより、ウェブサイトの制御下で必要なキー(バックスペース、デリート、矢印キーなど)だけを許可し、ユーザーにストレスのない入力体験を提供できる。

具体的な解決策は、onkeydownイベントというHTMLイベントハンドラとJavaScript関数を組み合わせることだ。onkeydownは、ユーザーがキーを押した瞬間に実行されるイベントであり、このタイミングで入力内容をチェックし、必要に応じて入力をキャンセルできる。

以下にその核となるJavaScript関数accountNumberConstraintの仕組みを解説する。

1const accountNumberConstraint = (event) => {
2  const allowedKeys = [
3    "Backspace", "Delete", "ArrowLeft", "ArrowRight", "Tab",
4    "Enter", "Home", "End"
5  ];
6
7  if (
8    !/^[0-9]$/.test(event.key) &&      // 1. 数字以外のキーをブロック
9    !allowedKeys.includes(event.key) && // 2. 許可された操作キー以外のキーをブロック
10    !(event.ctrlKey || event.metaKey)   // 3. Ctrl/Cmdキーとの組み合わせを許可
11  ) {
12    event.preventDefault();             // 4. それ以外の全てをブロック
13  }
14};

この関数は、キーボードでキーが押された際(eventオブジェクトでその情報を受け取る)に、以下の3つの条件を順にチェックする。

  1. 数字以外のキーをブロックする: !/^[0-9]$/.test(event.key)という部分で、押されたキーが数字(0から9)であるかどうかを正規表現で確認している。!が付いているので、「数字ではない」場合に次の条件をチェックすることになる。つまり、もし押されたキーが「a」や「b」のような数字以外の文字であれば、この条件に合致する。
  2. 許可された操作キー以外のキーをブロックする: !allowedKeys.includes(event.key)では、あらかじめ定義されたallowedKeysの配列(バックスペース、デリート、矢印キー、タブ、エンター、ホーム、エンドなど)に含まれていないキーであるかをチェックしている。これらのキーは、文字入力そのものではなく、テキストの編集やカーソル移動、フォーム内での移動に必要不可欠なキーだ。この条件に合致すれば、例えば「F5」のような機能キーや、開発者が想定していない不要なキー入力をブロックできる。
  3. Ctrl/Cmdキーとの組み合わせを許可する: !(event.ctrlKey || event.metaKey)という条件は、Ctrlキー(Windows/Linux)やMetaキー(MacのCmdキー)が同時に押されているかどうかを判断している。これにより、Ctrl+C(コピー)、Ctrl+V(ペースト)、Ctrl+Z(元に戻す)、Ctrl+A(全て選択)といったシステムレベルのショートカットキー操作を許可し、ユーザーが普段使い慣れている編集操作を妨げないようにする。

上記の3つの条件のいずれにも当てはまらない、つまり「数字でもなく、許可された操作キーでもなく、Ctrl/Cmdキーとの組み合わせでもない」と判断された場合に、event.preventDefault()が実行される。このメソッドは、ブラウザがそのキー入力に対して通常行う処理(例えば文字を入力フィールドに表示する)をキャンセルする役割を果たす。これにより、不適切な文字が入力フィールドに表示されることを完全に防げるのだ。

このカスタム関数を実際のHTML入力フィールドに適用する際には、type="text"を使うことで、type="number"特有のスピナーなどの問題を回避しつつ、JavaScriptで数字のみの入力を強制する。さらに、maxLength属性を使って入力可能な最大文字数を指定したり、onChangeイベントハンドラを使って入力内容が変更されるたびにアプリケーションの状態(データ)を更新したりといった、他の属性やイベントハンドラと組み合わせることで、より堅牢な入力フォームを実現できる。

例えば、Reactのようなフレームワークを使った開発では、以下のように記述される。

1<input
2  type="text"
3  placeholder="Enter Account No."
4  className="inputcc"
5  maxLength={10}
6  value={inputData.account_no}
7  onChange={(e) => setInputData({ ...inputData, account_no: e.target.value })}
8  onKeyDown={(event) => accountNumberConstraint(event)}
9/>

このコードでは、type="text"で柔軟なテキスト入力欄を確保しつつ、maxLength={10}で入力文字数を厳密に10文字に制限している。valueonChangeは、入力フィールドの値をReactの状態と同期させ、「制御されたコンポーネント」として扱うためのものだ。そして、最も重要なのがonKeyDown={(event) => accountNumberConstraint(event)}という部分で、ユーザーがキーを押すたびに先ほど説明したaccountNumberConstraint関数が呼び出され、リアルタイムで入力文字がフィルタリングされる。これにより、数字のみが入力され、かつコピー&ペーストやバックスペースなどの操作もスムーズに行える、理想的な入力フィールドが完成する。

最終的に、ウェブ上で数字のみを受け付ける入力フィールドを完璧に実装するには、HTMLのtype="text"による柔軟性、maxLength属性による文字数制限、そしてJavaScriptのonkeydownイベントを活用したカスタム関数によるリアルタイムなキー入力制御を組み合わせることが最善の解決策となる。この組み合わせにより、type="number"の課題や正規表現のみの制限による不満を解消し、ユーザーにとって使いやすく、開発者にとって管理しやすいフォームが実現できるのである。

【ITニュース解説】How to Make Input Element with Text Type to Take the Number as Text Perfectly | いっしー@Webエンジニア