「フォームの数値に3桁カンマを振りたい」という要望を受けました。
しかしinputのvalueが文字列になると色々都合が悪いので、inputの入力値はそのまま保持しつつ、見た目だけカンマ付きで表示する方法を実装しました。
同じ位置に擬似的なテキスト要素を重ねることで、「あたかもinput自体にカンマが表示されているように見せる」仕組みです。
デモ
See the Pen inputの3桁カンマ区切り by MEMORUKA (@memoruka) on CodePen.
経緯と狙い
依頼を受けた対象はプラン料金のシミュレーションを行うフォームです。
現状のフォームは各inputの入力値をもとにリアルタイムの計算がゴリゴリ入っています。なので単純にvalueを直接弄って文字列にするわけにはいきません。
かといって、そのあたりの計算ロジックを今更変更し、フォーカス時に一旦、文字列に変換して、数値はどこかに一時保存して…なんて正直言ってやりたくない。
そこで「inputのvalueはそのまま保持しつつ、CSSと最低限のJavaScriptで見た目だけカンマ付きにする」ということは出来ないかと考えました。
inputの調整
<input type="number" inputmode="numeric" min="0" max="99999" oninput="this.value = this.value.slice(0,5);">type = number
数値専用のinputフィールド。スマホでは数字キーボードが出ます。
inputmode = numeric
スマホでは数字キーボードが出ます。本来はtype = text用で、type = numberを利用した際は不要のはずですが、古いiOS端末だと併用しないと効かなかったので保険的に付けています。
min = 0 max = 99999
入力できる値の最小値:0と最大値:99999を制限。値は任意。※ただし手動入力で超えることは可能。そのためsliceを併用して対策。
oninput = this.value = this.value.slice(0,5)
入力イベントを先頭から5文字に制限。これにより最大5桁までしか入力できないようにしています(max = 99999と併用)。
各クラス要素の役割
<div class="number-container">
<input type="number" class="number-input number-input-style" inputmode="numeric" min="0" max="99999" oninput="this.value = this.value.slice(0,5);">
<span class="comma-box number-input-style"></span>
</div>/* コンテナ */
.number-container {
position: relative;
width: fit-content;
overflow: hidden;
&:not(:last-child) {
margin-bottom: 1em;
}
}
/* input と comma-box(カンマ表示用領域) のスタイルを合わせる */
.number-input-style {
box-sizing: border-box;
display: grid;
place-content: center start;
width: 200px;
font-family: "Yu Gothic", "Meiryo", "Helvetica Neue", "Hiragino Kaku Gothic ProN", "Arial", sans-serif;
font-size: 16px;
font-weight: 400;
padding: 0.5em;
border: 1px solid #ccc;
border-radius: 0;
line-height: 1;
/* type="number"のスピン削除 */
-moz-appearance: textfield;
&::-webkit-inner-spin-button,
&::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
}
/* カンマ区切りにしたいinput */
.number-input {
position: relative;
/* 通常時 - z-index:1でcomma-boxの後ろに。colorは透過 */
&:not(:focus) {
z-index: 1;
color: transparent;
caret-color: #333;
}
/* フォーカス時 - z-index:3でcomma-boxより前に */
&:focus {
z-index: 3;
background-color: #fff;
}
}
/* カンマ表示用。inputと同じ位置に配置する。 pointer-events:noneでクリックは無効化 */
.comma-box {
z-index: 2;
position: absolute;
inset: 0;
border: 0;
background: transparent;
margin: auto;
pointer-events: none;
}.number-container
inputとカンマ表示用要素の位置をpositionで合わせるための親コンテナ。
.number-input-style
inputとカンマ文字列(.comma-box)の共通スタイル。同じスタイルで見た目を一致させるのがポイント。
type = numberのスピンボタン(上下矢印)もここで削除。
.number-input
ユーザーが直接操作するinput。
通常は .comma-box が前面にあり見えませんが、フォーカス時にz-indexで前面に出します。
.comma-box
3桁カンマ付きの文字列を表示するための要素。
通常は、z-indexでinputの前面に表示されますが、pointer-events: none; によりクリックが無効化され、背後のinputが操作可能。inputにフォーカスされると、前後のz-indexが切り替わり、後ろに下がります。
javascript(jQuery)
$(function () {
function applyCommaFormat($input) {
const value = $input.val();
const $overlap = $input.next('.comma-box');
$overlap.text(value !== '' ? Number(value).toLocaleString() : '');
}
$('.number-input').on('blur input', function () {
applyCommaFormat($(this));
});
// 初期表示時にもカンマ区切りを適用
$('.number-input').each(function () {
applyCommaFormat($(this));
});
});toLocaleString()を使って、数値を3桁カンマで表示しています。
inputの値は数値のままなので、裏側での計算処理にも影響ありません。
参考にした記事
今回の件は、こちらの記事を参考にさせていただきました。
頭の中で描いていた、まさに「やりたかったこと」が紹介されていて、とても参考になりました。ありがとうございます。
ただ作者様自身も述べている通り、そのままでの実用化はちょい厳しかったので、必要項目を色々考えた次第です。
- inputの型をnumberにし、各種制限を導入
- スマホ対応や文字数制限など、細かな入力調整
- ページロード時から初期value値にもカンマが表示されるよう、初期処理を追加
まとめ
以上、inputに3桁カンマを表示しつつ、valueは数値のまま保持する方法でした。
inputのvalueを数値として維持しながら、3桁カンマを「見た目だけ」加えるこの方法は、既存の計算処理を壊すことなくカンマを表示できる、ちょっとした小技です。
先様に軽いノリでしれっとお願いされた際、案の1つとして参考にどうぞ。














