「管理画面だと、いま直している文章がページのどこに出るのかわからない」は、ヘッドレスCMSで納品したあと、更新担当の方からよく聞く声です。

EmDashなら、公開ページの上で文字や画像をクリックして直す「ビジュアル編集」が使えますが、直せる場所はテンプレートの書き方で決まります。EmDash 0.32.0の実装を読み、ローカル環境で動かして確かめた仕込み方をまとめました。読み終えると、クライアントに渡す「直せる範囲」を自分で設計できます。

直せるのは、テンプレートに印を付けた所だけ

ビジュアル編集で直せるのは、テンプレートで印を付けた要素だけです。押さえるポイントは3つあります。

  • 印は、取得した記事の edit を要素に展開して付ける
  • 印は編集モードのときだけ出力され、訪問者のHTMLには残らない
  • 編集用のツールバーが出るのは、Author以上のロールの人だけ
EmDashのビジュアル編集ツールバー。上はEditスイッチがオフ、下はオンでUNPUBLISHED CHANGESの表示とPublishボタンが出ている
上:ログイン中の通常表示。下:Editをオンにした状態。未公開の変更があるとPublishボタンが出る(ローカル環境で撮影)

印は edit を要素に展開して付ける

印の付け方は、{...post.edit.項目名} を要素に書き足すだけです。EmDashの取得関数が返す記事には、編集用の edit が最初から入っています(公式のAPIリファレンス)。

src/pages/blog/[slug].astro(抜粋)
<h1 class="post-title" {...post.edit.title}>{post.data.title}</h1>
<p class="post-summary" {...post.edit.summary}>{post.data.summary}</p>
<div class="post-featured-image" {...post.edit.featured_image}>
  <Image image={post.data.featured_image} />
</div>

展開すると、要素に data-emdash-ref という属性が付き、中身はコレクション名・記事ID・項目名・公開状態をまとめたJSONです。ページ側のスクリプトは、この属性でクリックされた項目を判断します。

編集モード以外では、何も出力されない

印の属性は、編集モードのときにしか出力されず、ふつうの訪問者が見るHTMLには1つも付かないので、表示速度や検索への影響はありません。

ローカル環境で同じ記事を見比べると、編集モードがオフなら data-emdash-ref は0個で、オンにすると見出し・要約・ヒーロー画像の3か所に付きます。編集モードでないときの edit が、何も返さない空の入れものになります(プレビューとビジュアル編集の公式ガイドにも同じ説明があります)。

ツールバーが出るのは Author 以上

ページ下部のツールバーは、ログイン中で Author(レベル30)以上 の人にだけ出て、公開の権限がないContributorには出ません。ロールの考え方は権限設計の記事でまとめています。

ツールバーの「Edit」スイッチを入れると、emdash-edit-mode というCookieが付き、ページが読み直されて編集モードに切り替わるしくみです。

クリックしたときの動きは、項目の型で4通りに分かれる

印の付いた要素をクリックしたときの動きは、その項目の型で決まり、ページ側のスクリプトがスキーマ情報を読み、次の4通りに振り分けます。

項目の型

クリックしたときの動き

短文・長文(string・text)

その場で文字を書き換える。Enterで確定、Escで元に戻す

画像(image)

小さな画面が開き、差し替え・削除・代替テキストの入力ができる

リッチテキスト(portableText)

本文がページ内のエディタになり、そのまま書ける

それ以外(選択肢・日付・参照など)

管理画面がその項目を指定して別タブで開く

EmDashのビジュアル編集で、公開ページの記事タイトルをクリックした状態。タイトル全体が選択され、青い枠で囲まれて編集できる
記事タイトルをクリックすると、全体が選択された状態で編集が始まる。青い枠が編集中の目印

短文・長文は、書式なしの文字として保存される

見出しや要約のような文字の項目は、書式なしの文字として保存されます。使っているのはブラウザ標準の contenteditable="plaintext-only" で、太字やリンクは付けられません(MDNの解説)。この指定が主要ブラウザで使えるようになったのは2025年3月です(web.devの発表)。

確定すると、要素の中の文字から前後の空白を除いたものが、そのまま項目に入ります。この「中の文字をまるごと保存する」動きが、後半で書く落とし穴の原因です。

本文の中にも、ページ上では直せないブロックがある

本文のエディタは、管理画面のエディタより機能を絞った簡易版です。実装のコメントによると、メディアの選択画面やセクションの挿入は持っていません。次のブロックは代わりの表示になります。

  • 表:読み取り専用の代わりの表示になる(公式ガイドに記載)
  • HTMLブロック:「HTML block (edit in admin)」と表示される
  • プラグインやテーマが足した独自ブロック:代わりの表示になる。中身のデータは保存しても消えない

このブログの囲み枠も独自ブロックなので、ページ上では直せないので、表や囲み枠は管理画面で直す、と更新担当の方に伝えておきます。

保存は下書き。公開はツールバーのボタンで行う

ページ上で直した内容は、まず下書きとして保存されます。保存と公開について、知っておきたい点は3つです。

  • 欄の外に出たときに、下書きとして保存される
  • ツールバーのPublishボタンは、確認なしで公開する
  • 編集モードの表示は、キャッシュを通らない
EmDashのビジュアル編集で公開されるまでの流れ。1 ツールバーでEditをオン、2 印の付いた所をクリック、3 欄の外に出ると下書き保存、4 Publishで公開

保存のタイミングは「欄の外に出たとき」

文字の項目は、Enterを押すか欄の外をクリックした時点で保存されます。本文のエディタも、欄から離れたときに保存する作りです。ツールバーに「Saved」と出れば、保存は済んでいます。

保存に使うのは、管理画面と同じ更新APIです。公開中の記事なら下書きだけが変わり、訪問者が見るページはそのままです。ツールバーには「Unpublished changes」とPublishボタンが出ます。

本文は、タブを閉じたときにも変更を送る作りです。ただし実装のコメントには、送れる量に64KBの上限があると書かれています。長い記事を大きく書き換える作業は、管理画面に任せるのが安全です。

Publishボタンは、確認なしで公開する

確認を挟まないのは、ページを見ながら素早く直すための作りなので、下書きがたまっている記事では、管理画面で差分を見てから公開するよう伝えておきます。

編集モードの表示は、キャッシュを通らない

編集モードとプレビューの表示は、EmDashのキャッシュを通らず、常にその時点のデータで描かれるので、直した結果がすぐ確かめられます。共有キャッシュでツールバーが出たり消えたりする件は、キャッシュの記事で書いた toolbar: "client" の設定で避けられます(設定の公式リファレンス)。

テンプレートで壊しやすい3か所

ビジュアル編集が効かない、おかしな値が入る、という原因はテンプレートの書き方にあります。このサイトで対処した1つを含め、壊しやすい所は次の3か所です。

  • 本文の配列を切ると、印が外れる
  • 飾りの文字まで、項目に保存される
  • リンクの中の印が、編集モードでクリックを奪う
ヘッドレスCMSのビジュアル編集で、テンプレートが壊れやすい3か所。本文の分割で印が外れる、飾った文字は飾りごと保存される、リンクの中ではクリックが遷移しない

1. 本文の配列を切ると、印が外れる

本文の配列を切り分けると、その部分はページ上で編集できなくなります。本文の印は、要素の属性ではなく配列そのものに見えない形で付いているからです。slice で作った新しい配列には、この印が引き継がれません。

このブログは、本文の途中に「あわせて読みたい」を差し込むため、本文を2つに割っているので、印が付いている(=編集モードの)ときは割らないようにしました。

src/lib/blog-toc.ts(抜粋)
export function splitAtMiddleH2(content: unknown): [unknown[], unknown[]] {
  if (!Array.isArray(content)) return [[], []];
  // 編集モードでは EmDash が配列に非列挙の編集メタを付ける。slice すると消えるので割らない
  if (Object.getOwnPropertyDescriptor(content, Symbol.for("__emdash"))) return [content, []];
  // ……真ん中の h2 の前で2つに割る
}

本文を並べ替えたり分けたりするテンプレートは珍しくないので、加工したら編集モードで本文がエディタに変わるかをいちど確かめてください。

2. 飾りの文字まで、項目に保存される

印を付けた要素の中に飾りの文字があると、確定したときに飾りごと項目に入ってしまいます。文字の項目は、要素の中の文字をまるごと保存するためです。次の例では、サイト名まで見出しの項目に入ってしまいます。

<!-- NG:「 | Tsudzuri」まで title に保存される -->
<h1 {...post.edit.title}>{post.data.title} | Tsudzuri</h1>

<!-- OK:印は値だけを包む要素に付ける -->
<h1><span {...post.edit.title}>{post.data.title}</span> | Tsudzuri</h1>

日付の整形や「〜年」のような単位、先頭のアイコンも同じです。印は、項目の値だけを表示している要素に付けるのが基本です。

3. リンクの中の印が、編集モードでクリックを奪う

リンクの中にある要素に印を付けると、編集モードではリンク先へ移動できなくなります。スクリプトがクリックを最初に受け取り、ページの移動を止めて編集を始める作りだからです。

一覧のカードで起きると、記事を開けなくなって困るので、このサイトも要素に印を付けているのは記事と実績の詳細ページだけです。

納品前に決めておくこと

印は全部の項目に付けるより、更新担当の方が「ページを見ながら直したい所」に絞るほうが使いやすくなります。このサイトでは、次のように分けました。

ページ

印を付けた項目

付けていない所と理由

ブログ記事

タイトル・要約・ヒーロー画像・本文

タグ(JSONで持っていて文字の編集に向かない)

実績の詳細

クライアント名・年・タイトル・要約・メイン画像・本文

技術スタックなどの一覧(管理画面のほうが崩れない)

一覧ページ

なし

リンクの中なので、移動を優先

決めたことは、管理画面の使い方と一緒に1枚にまとめて渡します。

  1. どのページの、どこがクリックで直せるか
  2. 表・囲み枠・HTMLブロックは管理画面で直すこと
  3. Publishボタンは確認なしで公開されること
  4. ツールバーを×で隠すと、次に管理画面を開くまで出ないこと

よくある質問

公開中のページを直したら、すぐ訪問者に見えますか?

見えません。ページ上での変更は下書きとして保存されます。Publishボタンか管理画面で公開するまで、訪問者には元の内容が表示されます。

Contributorのアカウントでもページ上で直せますか?

直せません。ツールバーが出るのはAuthor以上のロールです。Contributorの方には、これまでどおり管理画面で下書きを書いてもらいます。

ビジュアル編集を仕込むと、公開ページが重くなりませんか?

ふつうの訪問者には影響しません。印の属性は編集モードのときだけ出力され、ツールバーもログイン中の編集者にだけ差し込まれます。toolbar: "client" に切り替えた場合だけ、全員のページに小さな起動用スクリプトが1つ入ります。

まとめ

下書きを公開前に関係者へ見せる方法は、プレビュー実装の記事で書いています。

印の付け方ひとつで、納品後の「ここ、どこで直すんですか?」という問い合わせは減らせます。ヘッドレスCMSで作るサイトの、更新しやすさまで含めたテンプレート実装をお手伝いしているので、お問い合わせからお気軽にご相談ください。

本記事は2026年10月時点の情報です(EmDash 0.32.0で確認)。