日本語ドキュメント / フォームと入力 / Field
どの入力部品にも付けたい外枠です。ラベル、補足の文、そしてどの入力欄のものか分かるエラーの文をまとめます。
Shown in menus and the sidebar. You can change it later.
That address is missing its domain.
この部品は Input も使います。その CSS も一緒に読み込んでください。
<div style="display:grid;gap:var(--k-space-4);max-width:430px">
<div class="k-field">
<label class="lab">Workspace name <span class="opt">Optional</span><input class="input" type="text" value="Acme Studio"></label>
<p class="hint">Shown in menus and the sidebar. You can change it later.</p>
</div>
<div class="k-field" data-invalid>
<label class="lab">Billing email <span class="req">Required</span><input class="input" type="email" value="accounts@acme" aria-invalid="true"></label>
<p class="err"><svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="square" stroke-linejoin="bevel" aria-hidden="true"><circle cx="12" cy="12" r="8.5"/><path d="m9.5 9.5 5 5m0-5-5 5"/></svg> That address is missing its domain.</p>
</div>
</div>.k-field{display:grid;gap:var(--k-space-2);font-family:var(--k-font);text-align:start}
.k-field .lab{display:flex;align-items:baseline;gap:var(--k-space-2);font-size:var(--k-text-base);font-weight:550;color:var(--k-ink)}
.k-field .req{font-size:var(--k-text-xs);font-weight:500;color:var(--k-danger-ink)}
.k-field .opt{font-size:var(--k-text-xs);font-weight:500;color:var(--k-ink-3)}
.k-field .hint{font-size:var(--k-text-sm);color:var(--k-ink-3);line-height:var(--k-lh-small)}
.k-field .err{display:flex;gap:var(--k-space-1);align-items:center;font-size:var(--k-text-sm);font-weight:500;color:var(--k-danger-ink)}
.k-field[data-invalid] input,.k-field[data-invalid] textarea,.k-field[data-invalid] select{border-color:var(--k-danger)}
/* A label that wraps its control: text and badge on the first line, the control below at full width. */
.k-field .lab:has(> :is(input,textarea,select,.k-select)){flex-wrap:wrap;row-gap:var(--k-space-2)}
.k-field .lab > :is(input,textarea,select,.k-select){flex-basis:100%}
/* Controls size to the field including their padding and border, so a 100% wide input does not overflow it. */
.k-field :is(input,textarea,select){box-sizing:border-box;max-width:100%}
// Field: links the hint and, while the field is invalid, the error to the control
// with aria-describedby, and keeps aria-invalid in step with data-invalid. Existing
// IDs are kept; missing ones are generated, so a pasted sample can appear twice.
// When data-invalid is added after load (for example on submit), the error gets
// role="alert" so it is announced once; it is not announced while typing.
(() => {
let nextId = 0;
function ensureId(element, suffix) {
if (element.id) return element.id;
let id;
do { id = `kata-field-${++nextId}-${suffix}`; } while (document.getElementById(id));
element.id = id;
return id;
}
function sync(field, announce) {
const control = field.querySelector('input, textarea, select');
if (!control) return;
const label = field.querySelector('label');
if (label && !label.contains(control) && !label.htmlFor) label.htmlFor = ensureId(control, 'control');
const hint = field.querySelector('.hint');
const err = field.querySelector('.err');
const invalid = field.hasAttribute('data-invalid');
const own = [hint, err].filter(Boolean).map(el => el.id).filter(Boolean);
const ids = (control.getAttribute('aria-describedby') || '').split(/\s+/).filter(id => id && !own.includes(id));
if (hint) ids.push(ensureId(hint, 'hint'));
if (err && invalid) ids.push(ensureId(err, 'error'));
if (ids.length) control.setAttribute('aria-describedby', ids.join(' '));
else control.removeAttribute('aria-describedby');
if (invalid) control.setAttribute('aria-invalid', 'true');
else control.removeAttribute('aria-invalid');
if (err) {
if (invalid && announce) err.setAttribute('role', 'alert');
else if (!invalid) err.removeAttribute('role');
}
}
document.querySelectorAll('.k-field').forEach(field => {
if (field.hasAttribute('data-kata-ready')) return;
field.setAttribute('data-kata-ready', '');
sync(field, false);
new MutationObserver(() => sync(field, true)).observe(field, { attributes: true, attributeFilter: ['data-invalid'] });
});
})();
導入
npx @kajisho5/kataui add field手動で入れる場合:
tokens.cssをページで一度だけ読み込む- CSS タブの中身を、自分のスタイルシートに貼る
- HTML タブの中身を、使いたい場所に貼る。 この部品にはスクリプトがあります。HTML のあとで読み込むと、自分で動き始めます。
使いどころ
1つの入力部品を Field で包むと、ラベル・補足・エラーが離れずにまとまります。Field どうしを同じ間隔で縦に並べると、フォーム全体がそろって見えます。
アクセシビリティ
ラベルが入力部品を包むので、id やスクリプトがなくても名前が付きます。field.js(なくても動きます。即時実行の関数で、2回読み込んでも安全。Field ごとに MutationObserver を1つ使います)は、補足の文と、data-invalid が付いている間のエラーの文を、自動で作った id を使って aria-describedby でつなぎます。もとからある id や、作り手が書いた説明はそのまま残し、aria-invalid を data-invalid に合わせて切り替えます。読み込んだ時点で出ているエラーは読み上げません。あとから data-invalid が付いたとき(たとえば送信時)に、エラーへ role="alert" を1回だけ付けます。入力の途中では付けません。ラベル・バッジ・補足・エラーの文字は、ライト・ダークとも 4.83:1 以上です。Field の中の入力部品は box-sizing:border-box で大きさを決めるので、枠からはみ出しません。スクリーンリーダーと本物の日本語入力を手で確かめるまで Beta のままです。確認したのは Chromium だけです。
| キー | 動き |
|---|---|
| Tab | 次の入力部品へ移動 |
| Shift + Tab | 前の入力部品へ戻る |
英語版にだけある情報
静的チェックの結果・部品の構造(Anatomy)・読むトークン・使い方の例・関連する部品
この訳は、英語版の 2026-11-07 の内容をもとにしています。英語版の文が変わると、テストで知らせます。