Amazonで商品を見るセール会場へ

FigmaのノードIDでレイヤーを選択するプラグイン|取得・複数ID・ページ

FigmaのノードIDを指定すると、対象のレイヤーを探して選択できます。このプラグインは現在の選択からIDを取得し、複数行のIDを受け取って同じページのレイヤーを選びます。別ページのIDや取得できないIDはスキップとして数えます。

目次

ノードIDの表記と入力

入力扱い
12:34Plugin APIのIDとして使う
12-34単純な数値IDに限り12:34へ変換する
名前とTABとID最後のTABの後ろをIDとして使う
同じIDの複数行1件にまとめる

末尾の:00や、インスタンス内部のIDに含まれる文字は一律に削りません。URL全体ではなくnode-idの値を入力します。元の記事の取得欄は名前とTABとIDを出すため、その内容を入力へ戻せるようにしています。

選択の範囲と使い方

  1. 複製したファイルで起動します。
  2. 現在の選択からIDを取得するか、入力欄へ1行1IDで貼り付けます。
  3. 選択ボタンを押します。
  4. 最初の有効な対象のページへ移り、そのページに属する対象を選択します。
  5. 選択件数とスキップ件数を確認します。

Figmaのselectionは現在のページに属するレイヤーの配列です。異なるページを混ぜて一括選択することはしません。対象が1件も取得できない場合は、元の選択を残します。出典:ノード取得・ページ切り替えAPI、PageNode。

ファイルを作成する

FigmaのNew pluginで生成したmanifestを基に、次の設定を使います。掲載例ではidを省略しています。自分のmanifestに割り当てられたidがある場合はその値を保ち、サンプルの任意文字列に置き換えません。3ファイルを同じフォルダへ保存してください。

manifest.json

{
  "name": "ノードIDで選択",
  "api": "1.0.0",
  "main": "code.js",
  "ui": "ui.html",
  "editorType": [
    "figma"
  ],
  "documentAccess": "dynamic-page",
  "networkAccess": {
    "allowedDomains": [
      "none"
    ]
  }
}

code.js

figma.showUI(__html__, { width: 350, height: 520 });
function normalizeId(raw) {
  const fields = String(raw || "").trim().split("\t");
  const id = fields[fields.length-1].trim();
  return /^\d+-\d+$/.test(id) ? id.replace("-", ":") : id;
}
function pageOf(node) {
  let n = node;
  while (n && n.type !== "PAGE") n = n.parent;
  return n;
}
function reportSelection() {
  figma.ui.postMessage({ type: "selected-ids", ids: figma.currentPage.selection.map(n => n.name.replace(/[\t\r\n]/g," ")+"\t"+n.id) });
}
let busy = false;
figma.ui.onmessage = async msg => {
  if (!msg || busy) return;
  if (msg.type === "get-selected-ids") { reportSelection(); return; }
  if (msg.type !== "select-by-id" || !Array.isArray(msg.ids)) return;
  busy = true;
  try {
    const ids = Array.from(new Set(msg.ids.map(normalizeId).filter(Boolean)));
    const nodes = []; let page = null, skipped = 0;
    for (const id of ids) {
      let node;
      try { node = await figma.getNodeByIdAsync(id); } catch (_) { skipped++; continue; }
      if (!node || !("visible" in node)) { skipped++; continue; }
      const p = pageOf(node);
      if (!p || (page && p.id !== page.id)) { skipped++; continue; }
      page = p; nodes.push(node);
    }
    if (nodes.length) {
      await figma.setCurrentPageAsync(page);
      figma.currentPage.selection = nodes;
      figma.viewport.scrollAndZoomIntoView(nodes);
    }
    figma.ui.postMessage({ type: "selection-result", selected: nodes.length, skipped });
    reportSelection();
  } catch (_) { figma.ui.postMessage({ type: "selection-result", selected: 0, skipped: msg.ids.length }); }
  finally { busy = false; }
};
figma.on("selectionchange", reportSelection);

ui.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <title>ノードIDで選択</title>
    <style>
      body {
        font: 13px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Hiragino Sans", "Noto Sans JP", "メイリオ", sans-serif;
        margin: 12px;
      }
      textarea {
        width: 100%;
        height: 110px;
        box-sizing: border-box;
      }
      .row {
        margin: 10px 0;
      }
      .btn {
        padding: 8px 10px;
        border: 1px solid #ccc;
        background: #f7f7f7;
        cursor: pointer;
        border-radius: 6px;
      }
      .btn:active {
        transform: translateY(1px);
      }
      .muted {
        color: #666;
        font-size: 12px;
      }
      .grid {
        display: grid;
        grid-template-columns: 1fr auto;
        gap: 8px;
        align-items: center;
      }
      .stack {
        display: grid;
        gap: 8px;
      }
      hr {
        border: none;
        border-top: 1px solid #e5e5e5;
        margin: 14px 0;
      }
    </style>
  </head>
  <body>
    <div class="stack">
      <div class="row">
        <h3 style="margin: 0 0 8px">レイヤーIDで選択</h3>
        <textarea
          id="idsInput"
          placeholder="複数行にIDを貼り付けてください(例:I123:45)"
        ></textarea>
        <div class="grid">
          <span class="muted">各行を1つのIDとして処理します。</span>
          <button id="selectBtn" class="btn">選択</button>
        </div>
      </div>

      <hr />

      <div class="row">
        <h3 style="margin: 0 0 8px">現在の選択からID取得</h3>
        <div class="grid">
          <span class="muted">「名前 ID」形式で出力します。</span>
        </div>
        <textarea id="output" readonly></textarea>
        <div style="text-align: right">
          <button id="getBtn" class="btn">取得</button>
          <button id="copyBtn" class="btn">コピー</button>
        </div>
      </div>
    </div>

    <script>
      function splitLines(text) {
        return text.split(/\r?\n/);
      }
      function post(type, payload) {
        parent.postMessage(
          { pluginMessage: Object.assign({ type: type }, payload || {}) },
          "*"
        );
      }

      document.getElementById("selectBtn").onclick = function () {
        var raw = document.getElementById("idsInput").value;
        var ids = splitLines(raw);
        post("select-by-id", { ids: ids });
      };

      document.getElementById("getBtn").onclick = function () {
        post("get-selected-ids", {});
      };

      document.getElementById("copyBtn").onclick = function () {
        var text = document.getElementById("output").value;
        if (!text) {
          alert("コピーする内容がありません");
          return;
        }
        // 利用環境によって権限・対応が異なるため、失敗時は手動コピーを案内する
        navigator.clipboard.writeText(text).then(
          function () {
            alert("コピーしました");
          },
          function () {
            // フォールバック
            var ta = document.getElementById("output");
            ta.focus();
            ta.select();
            try {
              const copied = document.execCommand("copy");
              alert(copied ? "コピーしました" : "選択した文字を手動でコピーしてください");
            } catch (e) {
              alert("コピーに失敗しました");
            }
          }
        );
      };

      // プラグイン本体からのメッセージ受信
      window.onmessage = function (event) {
        if (event.source !== parent) return;
        var msg =
          event.data && event.data.pluginMessage
            ? event.data.pluginMessage
            : null;
        if (!msg) return;
        if (msg.type === "selection-result") alert("選択" + msg.selected + "件 / スキップ" + msg.skipped + "件");
        if (msg.type === "selected-ids" && msg.ids) {
          document.getElementById("output").value = msg.ids.join("\n");
        }
      };
    </script>
  </body>
</html>

取得できない場合とコピーの注意点

別ファイルのIDは、現在開いているファイル内の対象を指すとは限りません。ファイルとIDの組み合わせを確認します。PageやDocument自体はレイヤーの選択対象に含めません。

クリップボードへのコピーは、環境の権限・API対応によって失敗する場合があります。失敗時は出力欄の文字を選択して手動でコピーします。コピーの要求を送っただけで成功とは扱わない実装です。

ファイルキーとIDからURLを作る場合はレイヤーURLの一括出力を参照してください。

元記事の操作例

以下は元記事で掲載していた開発時の画面です。今回のコード改稿後に撮影した検証画像ではありません。現行の表示や変更結果は、複製したファイルで確認してください。

作成したプラグインを実行してレイヤーのノードID取得や選択などの動作を確認している様子。
2025年07月の元記事の掲載例。改稿後コードの検証画像ではありません。

検証範囲と関連ガイド

今回確認したのは掲載コードの構文と、該当する入力・例外処理のローカル模擬検証です。Figmaデスクトップアプリ上での動作確認とは区別しています。改稿後のコードと、元記事が参照していたGitHub上の版が一致するとは限りません。

開発環境と登録手順はFigmaプラグイン開発入門、公開はCommunityへの申請を参照してください。

サービス

Service

デザイン制作に関心がありましたら、ぜひ詳細をご覧ください。

次に学ぶ・作業環境を選ぶ

学習を続けたい方や、作業環境を整えたい方は、目的に合うガイドをご覧ください。

Figmaのおすすめ書籍

Figma用PCの選び方

周辺機器の優先度

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次