ノートエディタ
左にノート一覧、右に contenteditable のブロック本文。空のブロックで「/」を打つとブロックメニュー(見出し/箇条書き/区切り/本文)が出て、Enter で次のブロックへ進む。
プレビュー
入力
操作実際に入力して試せます。
仕様書
- 向く場面
- ブロック単位で書くノート・ドキュメント
- 「/」でブロック種別を呼ぶ編集体験
- 左に一覧・右に本文のメモアプリ
- 避ける場面
- 1 行だけの入力欄(textarea で足りる)
- リッチな装飾ツールバーが必要な文書作成
- 構成要素
- ノート一覧(題/更新日/新規)
- ノートの題
- 本文ブロック(本文/見出し/箇条書き/区切り)
- ブロックメニュー
- 狭幅の一覧トグル
- 持っている状態
- 通常
- ホバー
- フォーカス
- 押下中
- キーボード
ブロック内で Enter=次のブロック(IME 変換中は除く)、空で Backspace=削除。「/」でメニューが開き ↑↓ で選択・Enter で決定・Esc で閉じる。題で Enter→本文へ
- 支援技術
ブロックは role=textbox+aria-label(本文/見出し/箇条書き)+aria-placeholder。メニューは listbox/option+aria-selected で、開いている間はブロックの aria-activedescendant が選択項目を指す
- 動き
なし
デザインの要点
- 本文はブロックの縦積み。段落・見出し・箇条書きを同じ 1 行の器で扱うと、書く速度が落ちない
- 「/」のメニューは入力位置の直下に出し、↑↓と Enter で選べる。マウスに持ち替えさせない
- 装飾ツールバーは常設しない。書いているときに見えるのは文字と薄いプレースホルダーだけ
- 左の一覧は題と更新日だけ。本文の抜粋を出すと一覧が本文と競合して読みにくくなる
プロのサイトでの実例
実例は「型の使われ方」の観察であり、コード・ロゴの転載ではありません。サイト側の更新で見え方が変わることがあります。
実装メモ
contenteditable の内容はプレビュー内のメモリにだけ保存します。実装では blur や一定間隔で保存してください。IME 変換中の Enter(isComposing)は横取りしない実装になっています。
コード(コピーして使えます)
<div class="ne-app">
<aside class="ne-side" id="ne-side">
<div class="ne-side-head"><span class="ne-ws">ミナト工房</span><button type="button" class="ne-new" id="ne-new" aria-label="新しいノート">+</button></div>
<ul class="ne-notes" id="ne-notes"></ul>
</aside>
<main class="ne-main">
<button type="button" class="ne-side-toggle" id="ne-side-toggle" aria-expanded="false" aria-controls="ne-side">ノート一覧</button>
<div class="ne-doc" id="ne-doc">
<h1 class="ne-title" id="ne-title" contenteditable="true" spellcheck="false" data-placeholder="無題" aria-label="ノートの題" aria-placeholder="無題"></h1>
<div class="ne-blocks" id="ne-blocks"></div>
</div>
<div class="ne-menu" id="ne-menu" role="listbox" aria-label="ブロックの種類" hidden>
<button type="button" class="ne-menu-item is-active" role="option" id="ne-opt-h2" aria-selected="true" data-type="h2"><span class="ne-menu-ic">H</span><span><span class="ne-menu-name">見出し</span><span class="ne-menu-sub">大きめの見出し</span></span></button>
<button type="button" class="ne-menu-item" role="option" id="ne-opt-li" aria-selected="false" data-type="li"><span class="ne-menu-ic">•</span><span><span class="ne-menu-name">箇条書き</span><span class="ne-menu-sub">点付きのリスト</span></span></button>
<button type="button" class="ne-menu-item" role="option" id="ne-opt-hr" aria-selected="false" data-type="hr"><span class="ne-menu-ic">—</span><span><span class="ne-menu-name">区切り線</span><span class="ne-menu-sub">セクションを分ける</span></span></button>
<button type="button" class="ne-menu-item" role="option" id="ne-opt-p" aria-selected="false" data-type="p"><span class="ne-menu-ic">¶</span><span><span class="ne-menu-name">本文</span><span class="ne-menu-sub">ふつうの段落</span></span></button>
</div>
</main>
</div>