UI コピーの書き方
ハイパーメディアアプリでは言葉を描画するのはサーバです。アラートの タイトルも、トーストのメッセージも、エラーの一行も、すべて HTML として ワイヤ上を流れます。つまり UI コピーは契約の一部 — 周囲のマークアップと 同じだけの注意に値します。このページは、あなたのアプリが出力する 文字列のためのキットのボイス & トーンガイドです。キット自身の組み込み 文字列は末尾で扱います。
| 原則 | 実践では |
|---|---|
| 次のアクションのために書く | どのメッセージも、読んだ人が今なにをすべきか — フィールドを直す、リトライする、取り消す、やり直す — が分かる状態で終わること。 |
| プロトコル語彙より平易な言葉 | HTTP ステータス名、ステータスコード、例外クラス名はログと機械向け属性のもの。見えるテキストには決して出さない。 |
| 用語は UI 自身のラベルと一致させる | UI が呼ぶとおりに呼ぶ。ラベルが「表示名」なら、エラーも「表示名」— 「ユーザー名」でも display_name でもなく。 |
エラーメッセージ
Section titled “エラーメッセージ”エラーメッセージが答える問いは 2 つ — 何が起きたかとどう直すか。 1 メッセージにつき 1 つの内容だけを伝えます。
- HTTP ジャーゴンや内部識別子をエンドユーザーに見せないこと。
ステータステキスト、エラーコード、制約名は機械可読属性
(field-errors フラグメントの
data-code、data-field)に乗せます。見えるテキストは人間のため のものです。 - フィールドエラーはフィールドをそのラベル —
<label>の テキスト — で名指しします。読んだ人が見つけられるように。 - 失敗だけでなく直し方を述べる:「無効なメールアドレス」より 「有効なメールアドレスを入力してください」。
| Don’t | Do |
|---|---|
| Unprocessable Entity | 以下のエラーを修正してください。 |
| Error 422 | 変更は保存されていません。ハイライトされたフィールドを直して再送信してください。 |
| email: duplicate | このメールアドレスは既に登録されています。 |
| Constraint violation: members_email_key | このメールアドレスは既に登録されています。 |
| Invalid input | 2026-07-09 の形式で日付を入力してください。 |
左の列はステータスライン上では問題ありません — 422 Unprocessable Entity は HTTP ステータスとしては完全に正しい。人が読む
.hc-alert__title になった瞬間に、正しくなくなります。
トーストは読まれるのではなく、ちらりと見られるものです。配線は トーストレシピを参照。
- 短く、行動を先に — 目安は 6 語(全角 15 文字)以内。
- 「正常に」は不要 — トーストが出たこと自体が成功の合図です。 「メンバーを保存しました」であって「メンバーは正常に保存されま した!」ではなく。
- エラートーストは次にすべきことを言う — 「エラーが発生しました」ではなく「保存できませんでした。接続を確認 して再試行してください。」。
- スティッキーはユーザーの行動が必須のときだけ。
duration: 0は 自動消滅を外します。取り消しや再認証など、判断を運ぶトーストのために 取っておき、強調のためには使わないこと。 - アクションラベルは動詞 — 「元に戻す」「再試行」。 「こちらをクリック」は決して使わない。
| Don’t | Do |
|---|---|
| 項目は正常に削除されました! | 項目を削除しました |
| 保存中にエラーが発生しました | 保存できませんでした。しばらくして再試行してください。 |
| こちらをクリックで元に戻す | 元に戻す |
確認ダイアログ
Section titled “確認ダイアログ”confirm-action レシピは ダイアログの各部分を属性として公開しています — 漠然とした質問では なく、アクションを名指しするために使ってください:
- タイトルはアクションを名指しする:「本当によろしいですか?」 ではなく「請求書の削除」。
- 本文は結果を述べる: 何が失われるのか、取り消せるのか。
- 確定ボタンは動詞を繰り返す:「OK」「はい」ではなく「削除」— ボタンのラベルだけで、押すと何が起きるかが分かること。
<button class="hc-button" data-variant="error" data-hx-delete="/invoices/1024" data-hc-confirm="請求書 #1024 を完全に削除します。" data-hc-confirm-title="請求書の削除" data-hc-confirm-label="削除"> 削除</button>hc-empty ブロックは
ここに何が並ぶはずかを述べ、次の一歩を差し出します —
「データがありません」としか言わない空画面は行き止まりです:
<div class="hc-empty"> <p class="hc-empty__title">メンバーはまだいません</p> <p class="hc-empty__description"> 招待した人がここに表示されます。 </p> <div class="hc-empty__actions"> <button class="hc-button" data-variant="primary">メンバーを招待</button> </div></div>フィールドのヒントとエラー
Section titled “フィールドのヒントとエラー”役割が違えば、スロットも違います:
- ヒント(
.hc-field__hint)は常に真のガイダンス — 「共有されることはありません。」。フィールドが無効な間もミュート カラーのままです。 - エラー(バリデーション結果としての
.hc-field__message、または ビヘイビアが管理する.hc-field__errorスロット)は今直すべき こと — 「有効なメールアドレスを入力してください。」。エラー色で 表示され、問題が消えれば一緒に消えます。
ユーザーがフィールドを直したあとも役に立つ文なら、それはヒントです。 マークアップと再着色のルールは フィールド → ヒントとエラーの区別を 参照してください。
キット自身の文字列
Section titled “キット自身の文字列”ビヘイビアが自力で注入するもの — 「Dismiss」「Confirm」「Cancel」、
アップロードやページネーションのステータス行 — はすべて 1 つの
メッセージカタログで解決されるため、アプリは setMessages() 一発で
自分のボイスと言語に言い換えられます。
国際化(i18n)を参照。