インライン編集Inline edit
ふだんは値が文字で並んでいて、鉛筆のボタンを押すとその場所が入力欄と「保存」「キャンセル」に変わる。設定画面やプロフィールの項目を1つずつ直すのに使う。
表示例
- 表示名
- 山田 花子
-
Enter で保存、Esc で取り消し
アイコン: Font Awesome 7 Free(fa-solid / fa-regular)
別名・英語表記
- その場で編集
- インプレース編集
- クリックして編集
- 編集可能テキスト
- 鉛筆ボタンで編集
- Inline edit
実装例
<div class="x-inline-edit">
<dl class="x-inline-edit__list">
<div class="x-inline-edit__row">
<dt class="x-inline-edit__k">表示名</dt>
<dd class="x-inline-edit__v">
<span class="x-inline-edit__val">山田 花子</span>
<!-- 押すと、この dd の中身を下の行と同じ入力欄に差し替え、入力欄へフォーカスを移す -->
<button class="x-inline-edit__edit" type="button" aria-label="表示名を編集">
<i class="fa-solid fa-pen" aria-hidden="true"></i>
</button>
</dd>
</div>
<!-- 見本なので編集中の状態。保存・キャンセルのあとは値の表示に戻し、フォーカスを「編集」ボタンへ戻す -->
<div class="x-inline-edit__row x-inline-edit__row--on">
<dt class="x-inline-edit__k"><label class="x-inline-edit__lbl" for="x-inline-edit-i">部署</label></dt>
<dd class="x-inline-edit__v">
<input class="x-inline-edit__i" id="x-inline-edit-i" type="text" name="dept" value="デザイン部"
aria-describedby="x-inline-edit-h">
<div class="x-inline-edit__acts">
<button class="x-inline-edit__save" type="button">保存</button>
<button class="x-inline-edit__cancel" type="button">キャンセル</button>
</div>
<p class="x-inline-edit__h" id="x-inline-edit-h">Enter で保存、Esc で取り消し</p>
</dd>
</div>
</dl>
<!-- 保存したら「部署を保存しました」と書き換える。失敗したら入力欄を残して理由を出す -->
<p class="x-inline-edit__sr" role="status"></p>
</div>
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-inline-edit,
.x-inline-edit *:not([class*="fa-"]),
.x-inline-edit *:not([class*="fa-"])::before,
.x-inline-edit *:not([class*="fa-"])::after {
box-sizing: border-box;
/* 貼った先の既定の書体に引きずられないようにする。書体が変わると
文字の幅と高さが変わり、枠のサイズまでずれる */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}
.x-inline-edit {
width: 320px;
max-width: 100%;
color: #1b2028;
font-size: 14px;
}
.x-inline-edit__list {
margin: 0;
border: 1px solid #7f8a99;
border-radius: 8px;
background: #fff;
}
.x-inline-edit__row {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 10px 12px;
}
.x-inline-edit__row + .x-inline-edit__row {
border-top: 1px solid #d5dae1;
}
.x-inline-edit__k {
flex: none;
width: 56px;
padding-top: 7px;
color: #5b6472;
font-size: 12px;
font-weight: 700;
}
.x-inline-edit__v {
display: flex;
flex: 1 1 auto;
flex-wrap: wrap;
align-items: center;
gap: 6px;
min-width: 0;
margin: 0;
}
.x-inline-edit__val {
flex: 1 1 auto;
min-width: 0;
padding: 6px 0;
overflow-wrap: anywhere;
}
/* 鉛筆は常に見せる。ホバーでしか出ないと、タッチとキーボードの利用者が編集できると気づかない */
.x-inline-edit__edit {
width: 32px;
height: 32px;
flex: none;
border: 1px solid #7f8a99;
border-radius: 6px;
background: #fff;
color: #1b2028;
font-size: 12px;
cursor: pointer;
}
.x-inline-edit__edit:hover {
background: #eef2ff;
}
.x-inline-edit__i {
flex: 1 1 100%;
min-width: 0;
height: 36px;
padding: 0 10px;
border: 1px solid #1d4ed8;
border-radius: 6px;
background: #fff;
color: #1b2028;
font: inherit;
font-size: 14px;
}
.x-inline-edit__acts {
display: flex;
gap: 6px;
}
.x-inline-edit__save,
.x-inline-edit__cancel {
height: 30px;
padding: 0 12px;
border: 1px solid #1d4ed8;
border-radius: 6px;
font: inherit;
font-size: 12px;
font-weight: 700;
cursor: pointer;
}
.x-inline-edit__save {
background: #1d4ed8;
color: #fff;
}
.x-inline-edit__cancel {
border-color: #7f8a99;
background: #fff;
color: #1b2028;
}
.x-inline-edit__h {
margin: 0;
color: #5b6472;
font-size: 11px;
}
.x-inline-edit__edit:focus-visible,
.x-inline-edit__i:focus-visible,
.x-inline-edit__save:focus-visible,
.x-inline-edit__cancel:focus-visible {
outline: 2px solid #1d4ed8;
outline-offset: 1px;
}
.x-inline-edit__sr {
position: absolute;
width: 1px;
height: 1px;
margin: 0;
overflow: hidden;
white-space: nowrap;
clip-path: inset(50%);
}
AIへの指示文
「インライン編集(Inline edit)」を実装してください。
## これは何か
ふだんは値が文字で並んでいて、鉛筆のボタンを押すとその場所が入力欄と「保存」「キャンセル」に変わる。設定画面やプロフィールの項目を1つずつ直すのに使う。
## 使いどころ
- プロフィール・設定・一覧の1項目のように、たまに1か所だけ直す値を、画面を移らずに直してもらうとき
- 読む時間が長く、直す時間が短い画面で、全部を入力欄で並べると読みにくくなるとき
## 実装の要件
- 項目名と値の組(dl など)+ 値の横に button[aria-label="〇〇を編集"]。編集中は同じ場所を label + input + 保存 / キャンセルの button に差し替える
- Enter で保存、Esc で取り消し。どちらのあとも表示に戻し、フォーカスを編集ボタンへ戻す
- 保存中はボタンを押せなくして二重送信を防ぎ、終わったら role="status" の領域に結果を書く
- 日本語の変換を確定・取り消す Enter・Esc では保存も取り消しもしない。keydown で event.isComposing が true か event.keyCode === 229 のときは何もしない。Safari 26 以前は確定の Enter で isComposing が false になる(27 で修正)ので、keyCode の確認を外さない
- 編集できることを見た目で示す。鉛筆のボタンを常に出しておく。ホバーでしか出ないと、タッチやキーボードの利用者は気づけない
- 値そのものをクリックで入力欄に変えるだけにしない。値の横に「編集」ボタンを置けば、キーボードでも読み上げでも操作が分かる
- 欄の外をクリックしたときに保存するのか取り消すのかを決め、画面全体でそろえる。入力途中の内容が黙って消える作りは避ける
- 保存に失敗したら入力欄を開いたまま残し、理由を欄の近くに出す。値の表示に戻してしまうと、何が保存されたのか分からなくなる
- 何項目もまとめて入れる画面には使わない。最初から入力欄を並べたフォーム(テキストフィールド)のほうが速い
## アクセシビリティの要件
- 編集ボタンは button にして、aria-label で「表示名を編集」のように何を直すのかを示す。鉛筆の絵だけでは伝わらない
- 編集を始めたら入力欄へフォーカスを移し、保存かキャンセルのあとは編集ボタンへ戻す。消えた要素にフォーカスが残ると body へ落ちる
- 入力欄は label で項目名と結び、「Enter で保存、Esc で取り消し」の説明を aria-describedby で添える
- 保存できたことを role="status" の領域で「部署を保存しました」と伝える(達成基準 4.1.3 ステータスメッセージ)
- フォーカスの位置が見えるよう :focus-visible に枠を出す(達成基準 2.4.7 フォーカスの可視化)
## 参考にする実装
この形を出発点にして、プロジェクトの命名規則・色・余白に合わせて調整してください。
```html
<div class="x-inline-edit">
<dl class="x-inline-edit__list">
<div class="x-inline-edit__row">
<dt class="x-inline-edit__k">表示名</dt>
<dd class="x-inline-edit__v">
<span class="x-inline-edit__val">山田 花子</span>
<!-- 押すと、この dd の中身を下の行と同じ入力欄に差し替え、入力欄へフォーカスを移す -->
<button class="x-inline-edit__edit" type="button" aria-label="表示名を編集">
<i class="fa-solid fa-pen" aria-hidden="true"></i>
</button>
</dd>
</div>
<!-- 見本なので編集中の状態。保存・キャンセルのあとは値の表示に戻し、フォーカスを「編集」ボタンへ戻す -->
<div class="x-inline-edit__row x-inline-edit__row--on">
<dt class="x-inline-edit__k"><label class="x-inline-edit__lbl" for="x-inline-edit-i">部署</label></dt>
<dd class="x-inline-edit__v">
<input class="x-inline-edit__i" id="x-inline-edit-i" type="text" name="dept" value="デザイン部"
aria-describedby="x-inline-edit-h">
<div class="x-inline-edit__acts">
<button class="x-inline-edit__save" type="button">保存</button>
<button class="x-inline-edit__cancel" type="button">キャンセル</button>
</div>
<p class="x-inline-edit__h" id="x-inline-edit-h">Enter で保存、Esc で取り消し</p>
</dd>
</div>
</dl>
<!-- 保存したら「部署を保存しました」と書き換える。失敗したら入力欄を残して理由を出す -->
<p class="x-inline-edit__sr" role="status"></p>
</div>
```
```css
/* 貼った先のリセットに頼らないよう、この部品の中だけ border-box にする */
.x-inline-edit,
.x-inline-edit *:not([class*="fa-"]),
.x-inline-edit *:not([class*="fa-"])::before,
.x-inline-edit *:not([class*="fa-"])::after {
box-sizing: border-box;
/* 貼った先の既定の書体に引きずられないようにする。書体が変わると
文字の幅と高さが変わり、枠のサイズまでずれる */
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Sans", "Noto Sans JP", "Yu Gothic UI", Meiryo, sans-serif;
}
.x-inline-edit {
width: 320px;
max-width: 100%;
color: #1b2028;
font-size: 14px;
}
.x-inline-edit__list {
margin: 0;
border: 1px solid #7f8a99;
border-radius: 8px;
background: #fff;
}
.x-inline-edit__row {
display: flex;
align-items: flex-start;
gap: 12px;
padding: 10px 12px;
}
.x-inline-edit__row + .x-inline-edit__row {
border-top: 1px solid #d5dae1;
}
.x-inline-edit__k {
flex: none;
width: 56px;
padding-top: 7px;
color: #5b6472;
font-size: 12px;
font-weight: 700;
}
.x-inline-edit__v {
display: flex;
flex: 1 1 auto;
flex-wrap: wrap;
align-items: center;
gap: 6px;
min-width: 0;
margin: 0;
}
.x-inline-edit__val {
flex: 1 1 auto;
min-width: 0;
padding: 6px 0;
overflow-wrap: anywhere;
}
/* 鉛筆は常に見せる。ホバーでしか出ないと、タッチとキーボードの利用者が編集できると気づかない */
.x-inline-edit__edit {
width: 32px;
height: 32px;
flex: none;
border: 1px solid #7f8a99;
border-radius: 6px;
background: #fff;
color: #1b2028;
font-size: 12px;
cursor: pointer;
}
.x-inline-edit__edit:hover {
background: #eef2ff;
}
.x-inline-edit__i {
flex: 1 1 100%;
min-width: 0;
height: 36px;
padding: 0 10px;
border: 1px solid #1d4ed8;
border-radius: 6px;
background: #fff;
color: #1b2028;
font: inherit;
font-size: 14px;
}
.x-inline-edit__acts {
display: flex;
gap: 6px;
}
.x-inline-edit__save,
.x-inline-edit__cancel {
height: 30px;
padding: 0 12px;
border: 1px solid #1d4ed8;
border-radius: 6px;
font: inherit;
font-size: 12px;
font-weight: 700;
cursor: pointer;
}
.x-inline-edit__save {
background: #1d4ed8;
color: #fff;
}
.x-inline-edit__cancel {
border-color: #7f8a99;
background: #fff;
color: #1b2028;
}
.x-inline-edit__h {
margin: 0;
color: #5b6472;
font-size: 11px;
}
.x-inline-edit__edit:focus-visible,
.x-inline-edit__i:focus-visible,
.x-inline-edit__save:focus-visible,
.x-inline-edit__cancel:focus-visible {
outline: 2px solid #1d4ed8;
outline-offset: 1px;
}
.x-inline-edit__sr {
position: absolute;
width: 1px;
height: 1px;
margin: 0;
overflow: hidden;
white-space: nowrap;
clip-path: inset(50%);
}
```
## 出力の約束
- HTML と CSS を分けて出す。JavaScript が要るときは素の JavaScript で書き、UIフレームワークは使わない。
- 参考実装がアイコンに Font Awesome のクラスを使っている場合は、プロジェクトで使っているアイコンかインライン SVG に置き換えてよい。
- 上のアクセシビリティ要件を満たす。満たせない箇所があるときは、理由を添えて先に知らせる。
- 色・角丸・余白は既存のデザイントークンがあればそれを使う。無ければ CSS 変数として切り出す。
使いどころ
- プロフィール・設定・一覧の1項目のように、たまに1か所だけ直す値を、画面を移らずに直してもらうとき
- 読む時間が長く、直す時間が短い画面で、全部を入力欄で並べると読みにくくなるとき
注意点
- 編集できることを見た目で示す。鉛筆のボタンを常に出しておく。ホバーでしか出ないと、タッチやキーボードの利用者は気づけない
- 値そのものをクリックで入力欄に変えるだけにしない。値の横に「編集」ボタンを置けば、キーボードでも読み上げでも操作が分かる
- 欄の外をクリックしたときに保存するのか取り消すのかを決め、画面全体でそろえる。入力途中の内容が黙って消える作りは避ける
- 保存に失敗したら入力欄を開いたまま残し、理由を欄の近くに出す。値の表示に戻してしまうと、何が保存されたのか分からなくなる
- 何項目もまとめて入れる画面には使わない。最初から入力欄を並べたフォーム(テキストフィールド)のほうが速い
アクセシビリティの要点
- 編集ボタンは button にして、aria-label で「表示名を編集」のように何を直すのかを示す。鉛筆の絵だけでは伝わらない
- 編集を始めたら入力欄へフォーカスを移し、保存かキャンセルのあとは編集ボタンへ戻す。消えた要素にフォーカスが残ると body へ落ちる
- 入力欄は label で項目名と結び、「Enter で保存、Esc で取り消し」の説明を aria-describedby で添える
- 保存できたことを role="status" の領域で「部署を保存しました」と伝える(達成基準 4.1.3 ステータスメッセージ)
- フォーカスの位置が見えるよう :focus-visible に枠を出す(達成基準 2.4.7 フォーカスの可視化)