入力マスク
stimeo--input-mask
決めた形に沿って入力を整えます。カーソルの位置は動きません。
電話番号や郵便番号のように形の決まった入力を、打ちながら整えます。括弧やハイフンは自動で入り、その桁に入れられない文字は受け付けません。カーソルは受け付けなかった打鍵でも動かず、区切りをまたぐ削除でも 1 文字ずつ消えていきます。日本語入力の変換中には手を出さず、全角のまま確定した数字は、その桁に入れられるときだけ半角として受け取ります。画面には整えた形を出し、サーバへは記号を除いた値を送ります。読み取り専用の欄では、ページが描いた値をそのまま残します。
実行中
サーバへ送られる生値:
(空)
キーボード操作
このコンポーネント自体はキーボード操作を持ちません。
<%# Markup for the input mask demo.
The controller formats the field in place against the pattern (9=digit), inserts
the separators, rejects non-digits, preserves the caret, and syncs the raw value
to the hidden field. demo.js mirrors that hidden raw value (and the complete flag)
into the visible readout below, since the unmask field is hidden. %>
<div class="mask-demo">
<form class="mask-demo__form">
<label class="mask-demo__field">
<span><%= t("components.input_mask.demo.label") %></span>
<input type="text" class="demo-input" inputmode="numeric"
data-controller="stimeo--input-mask"
data-stimeo--input-mask-pattern-value="(999) 999-9999"
data-action="input->stimeo--input-mask#format"
aria-describedby="mask-hint"
placeholder="<%= t("components.input_mask.demo.placeholder") %>">
<input type="hidden" name="phone" data-stimeo--input-mask-unmask>
</label>
<p id="mask-hint" class="mask-demo__hint"><%= t("components.input_mask.demo.hint") %></p>
</form>
<p class="mask-demo__raw"
data-empty="<%= t("components.input_mask.demo.empty") %>"
data-complete="<%= t("components.input_mask.demo.complete") %>">
<%= t("components.input_mask.demo.raw_label") %>
<code data-mask-demo="raw"><%= t("components.input_mask.demo.empty") %></code>
<span data-mask-demo="status"></span>
</p>
</div>
/*
* Presentation-only styles for the input mask demo.
* The library formats the value, preserves the caret, and reflects
* data-mask-complete / data-mask-empty; this CSS owns layout and the readout, and
* can react to the completion flag for a finished-state affordance.
*/
.mask-demo {
display: flex;
flex-direction: column;
gap: 0.75rem;
max-width: 28rem;
}
.mask-demo__field {
display: flex;
flex-direction: column;
gap: 0.25rem;
font-size: 0.9rem;
font-weight: 600;
}
/* The library marks a fully-filled mask with data-mask-complete. */
.mask-demo .demo-input[data-mask-complete] {
border-color: var(--leaf-500);
}
.mask-demo__hint {
margin: 0.25rem 0 0;
font-size: 0.8rem;
font-weight: 400;
color: var(--color-text-muted);
}
.mask-demo__raw {
margin: 0;
font-size: 0.9rem;
}
.mask-demo__raw code {
padding: 0.1rem 0.4rem;
border-radius: 0.25rem;
background: var(--surface-subtle);
font-family: ui-monospace, monospace;
}
// Consumer-side JS for the input mask demo (demo-only).
// The raw (unmasked) value the controller syncs lives in a hidden field, so this
// mirrors it into a visible readout from the change event, and shows a "complete"
// note when every slot is filled. Localized strings come from data attributes.
const readout = document.querySelector(".mask-demo__raw");
const raw = document.querySelector("[data-mask-demo='raw']");
const status = document.querySelector("[data-mask-demo='status']");
if (readout && raw) {
const render = (event) => {
const { unmasked, complete } = event.detail;
raw.textContent = unmasked || readout.dataset.empty;
if (status) status.textContent = complete ? ` ${readout.dataset.complete}` : "";
};
// change carries your edits; reconcile carries a value the controller decided
// (a server-rendered value normalized on connect), and both share the detail.
document.addEventListener("stimeo--input-mask:change", render);
document.addEventListener("stimeo--input-mask:reconcile", render);
}
これらのスタイルは共通のデザイントークン(ライト/ダーク両対応)を使います。共通スタイルも一緒にコピーし、ルート要素の data-theme を切り替えればダークになります。
このコンポーネントを動かすために HTML へ記述する data-* 属性です。ルート要素に下の data-controller を付け、その内側に各 target / value / action を配置します。
ルート要素に付与
data-controller="stimeo--input-mask"
値(Values)
| 名前 | 説明 | 属性 |
|---|---|---|
pattern
|
マスクパターン(9 / a / * トークンとリテラル。既定は空)。 |
data-stimeo--input-mask-pattern-value |
tokens
|
プレースホルダ→正規表現ソースの対応を表す JSON 文字列。指定キーが既定にマージされ、読み取れない宣言は既定に戻る。 | data-stimeo--input-mask-tokens-value |
unmaskToHidden
|
生値を hidden フィールドへ同期するか(既定 true)。false にすると、それまで同期していた欄を空にする。 |
data-stimeo--input-mask-unmask-to-hidden-value |
アクション
| 名前 | 説明 | アクション |
|---|---|---|
format
|
キャレットを保ったまま整形する。input イベントに結線。 |
stimeo--input-mask#format |
イベント
| 名前 | 説明 | イベント |
|---|---|---|
change
|
利用者の編集で値が変わったとき発火。detail に masked・unmasked・complete を伴う。 |
stimeo--input-mask:change |
reconcile
|
接続時の正規化や pattern / tokens / unmaskToHidden の変更で、コントローラが値を決め直したとき発火。detail は change と同じ。 |
stimeo--input-mask:reconcile |
状態フック
ライブラリが操作するのはこれらの ARIA / data 属性、カスタムプロパティだけです。見た目は利用側 CSS がこれらに反応して作ります([aria-selected] / [aria-expanded] / var(--stimeo--…) などのセレクタでフックします)。
| フック | 対象 | 意味 |
|---|---|---|
data-mask-complete |
マスク対象の入力欄 | パターンの全トークンが埋まると "true"。 |
data-mask-empty |
マスク対象の入力欄 | 値が空のあいだ "true"(プレースホルダ表示制御など)。 |