【実務・中級編】Penpotのコンポーネントバリアント応用術:状態遷移をスマートに管理するネスト構造の設計手法 – UI/UX・デザインツール活用バイブル

Penpotのコンポーネントバリアント応用術:状態遷移をスマートに管理するネスト構造の設計手法

テックリードの君なら、こんな絶望を味わったことが一度はあるはずだ。
「デザインファイル上では綺麗に並んでいたコンポーネントが、いざコードに落とし込む段階になって破綻している」「ちょっとした状態(ホバー、フォーカス、ローディング)を追加しただけで、FigmaやPenpotのバリアント数が爆発し、デザイナーもエンジニアも迷子になっている」――。

オープンソースの旗手であるPenpotは、SVGをネイティブフォーマットとして採用し、CSSのメンタルモデル(FlexboxやGrid)をそのままデザインツールに持ち込んだ、我々エンジニアにとって最高のご褒美のようなツールだ。しかし、その自由度ゆえに、適当にコンポーネントを作ると「メンテ不能のゴミ山」がすぐに出現する。

今回は、Penpotのポテンシャルを極限まで引き出し、「エンジニアのコーディング規約と1:1で同期する」コンポーネント設計の極意を伝授する。バリアントの限界を突破し、状態遷移を美しく制御するネスト構造の構築手法をマスターしよう。

—

1. バリアント機能の限界を超えるネスト構造の活用法

単一のコンポーネントにすべての状態(Default, Hover, Focus, Disabled, Loading…)を詰め込もうとするのは、アンチパターンだ。プロパティの直積(組み合わせ)でバリアント数が爆発し、デザイナーはプロパティ選択地獄に陥り、エンジニアは何を参照すべきか迷う。

ここで導入すべきのが、「アトミック・ステート・ネスト(Atomic State Nesting)」という設計思想だ。

思考のフレームワーク:構造と状態の分離

コンポーネントの本質は以下の2つに分解できる。
1. ストラクチャ(構造): アイコン、テキスト、ボーダー、背景など、見た目の骨組み。
2. ステート(状態): ホバー時の色変化、フォーカス時のリング、無効時の透過度など。

Penpotでは、「ロジカル・コンポーネント(親)」の中に「ステートレスなビジュアル・コンポーネント(子)」をネストさせることで、バリアントの爆発を防ぐ。

実践:プライマリボタンのネスト構造

  • Level 1 (Atom): `_Button/Base`(Auto-Layoutのパディング、タイポグラフィ、角丸のみを持つ。状態を持たない)
  • Level 2 (Molecule): `Button/Primary`(`_Button/Base`を内包し、Variantプロパティとして `State [Default / Hover / Focus / Disabled]` のみをコントロールする)

親コンポーネントは状態の見た目(CSSの疑似クラスに相当する部分)のみを管理し、実際のコンテンツ(ラベルやアイコン)はオーバーライド(インスタンス上での書き換え)に委ねる。これにより、バリアント数を最小限($O(N)$のオーダー)に抑え込むことができる。

—

2. ホバー、フォーカス、ディセーブル状態を効率よく管理する命名規則

チーム開発、特にデザイナーとエンジニアが混ざるプロジェクトにおいて、命名規則の欠如は致命傷になる。Penpotのレイヤーパネルおよびコンポーネント名規約は、そのままCSS/Tailwind CSSのクラス設計と直結させるべきだ。

スラッシュ(`/`)を用いたFigma/Penpot共通の階層命名規則

Penpotのプロパティ機能とオートレイアウトを最大限に活かすため、以下の命名スキームをチームの絶対ルールとして定めよ。

> `[カテゴリー] / [コンポーネント名] / [バリアント属性]=[値]`

具体例:

  • `Components / Button / Type=Primary, State=Default`
  • `Components / Button / Type=Primary, State=Hover`
  • `Forms / Input / Size=Md, State=Error`

開発スピードを加速させるキーボードショートカット(Penpot版)

マウス操作でレイヤーをポチポチしている時間はエンジニアの寿命を削る。以下のショートカットを指に覚え込ませろ。

| ショートカット (Mac / Windows) | アクション | テックリードの活用文脈 |
| :— | :— | :— |
| `⌥ + ⌘ + K` / `Alt + Ctrl + K` | コンポーネント化 (Create Component) | 素早くアトミックパーツを切り出す時 |
| `⌥ + ⏎` / `Alt + Enter` | コンポーネントのメインに移動 (Go to main) | インスタンスから親の構造を瞬時に確認・修正する時 |
| `Shift + A` | オートレイアウト追加 (Add Auto Layout) | Flexbox構造をコンポーネントに即座に適用する時 |
| `⌘ + G` / `Ctrl + G` | グループ化 | レイヤー構造を整理し、ネストの境界を明確にする時 |

—

3. エンジニアのコーディング規約と完全に一致させるコンポーネント設計のコツ

優秀なUI/UXエンジニアならこう考えるはずだ。「このPenpotのデザイン、そのままTailwind CSSのコンポーネント設計に落とし込めるよな?」と。

デザインとコードの乖離をゼロにするために、Penpotのパラメータ設計をコンポーネント指向フレームワーク(React / Vue / Svelte等)のPropsと完全同期させる。

設計の同期ルール

1. Penpotの「Booleanプロパティ」 $\rightarrow$ Reactの `isLoading?: boolean`, `hasIcon?: boolean`
2. Penpotの「Variantプロパティ」 $\rightarrow$ Reactの `variant?: ‘primary’ | ‘secondary’`, `size?: ‘sm’ | ‘md’ | ‘lg’`
3. Penpotの「Textプロパティ」 $\rightarrow$ Reactの `children: string`

この規約を徹底することで、デザイナーがPenpot上で設定したプロパティ名と、エンジニアが書くコンポーネントのインタフェース(TypeScriptの型定義)が完全に一致する。

—

🛠️ 生産性を極限まで高める神プラグイン & チーム設定共有ルール

1. 絶対入れるべき拡張機能・プラグイン

Penpotはエコシステムが急速に拡大している。以下のプラグイン(または公式提供の拡張機能・ワークフロー)をチーム全員に強制インストールさせろ。

  • Design Token Exporter: Penpot上のカラー、タイポグラフィ、スペーシングをJSONとしてエクスポートし、GitHub Actions経由でコード側のCSS変数(Design Tokens)と自動同期させるパイプラインを構築せよ。
  • Accessibility Checker (Contrast Tools): WCAG 2.1のコントラスト比をバリアントごとにリアルタイム検証し、アクセシビリティ負債の発生をデザイン段階でブロックする。

2. チーム開発で役立つ設定の共有化ルール

  • カラーパレットとタイポグラフィの「Shared Libraries」化:

プロジェクト固有の自由な色入力を禁止する。すべてのカラーはDesign Tokens(Primitives / Semantic)としてライブラリ登録し、デザイナーは必ずセマンティックトークン(例: `color-action-primary-default`)を使用する。

  • グリッド・スペーシングの強制:

スペーシングは `4px` または `8px` のグリッドシステム($4, 8, 12, 16, 24, 32, 48, 64$)に厳格に縛る。PenpotのGrid/Layout設定でこれを視覚的に強制する。

—

📄 実用的な設定ファイル(JSON)のベストプラクティス構成例

デザインシステムとコードベースの架け橋となる、Design TokensのJSONファイル(W3C Design Tokens Community Group形式準拠)のベストプラクティスを提示する。これをPenpotのエクスポート結果と紐付け、エンジニアリング側にシームレスに流し込む。

{
“button”: {
“primary”: {
“background”: {
“value”: “{color.brand.indigo.600}”,
“type”: “color”,
“comment”: “プライマリボタンのデフォルト背景色。Tailwindのbg-indigo-600に対応”
},
“background-hover”: {
“value”: “{color.brand.indigo.700}”,
“type”: “color”,
“comment”: “ホバー時の背景色。CSSの :hover 疑似クラスに直結”
},
“text”: {
“value”: “{color.neutral.white}”,
“type”: “color”,
“comment”: “ボタン内のテキストカラー”
},
“border-radius”: {
“value”: “{spacing.radius.md}”,
“type”: “borderRadius”,
“comment”: “角丸の設定。rounded-md (6px) に対応”
}
}
},
“color”: {
“brand”: {
“indigo”: {
“600”: { “value”: “#4F46E5”, “type”: “color” },
“700”: { “value”: “#4338CA”, “type”: “color” }
}
},
“neutral”: {
“white”: { “value”: “#FFFFFF”, “type”: “color” }
}
},
“spacing”: {
“radius”: {
“md”: { “value”: “6px”, “type”: “dimension” }
}
}
}

—

結び:ツールに使われるな、ツールを飼いならせ

優れたUI/UXエンジニアは、ツールの機能表を眺めて満足したりはしない。「このツールは内部でどういうDOM構造/SVGを描画し、どのようなCSSモデルで動いているか」を理解し、その特性をハックしてチームの生産性を最大化する。

Penpotのネスト構造と厳格な命名規則、そしてコードとの同期。これらを今日から君のチームのワークフローに導入しろ。
無駄な修正指示のチャットが消え、デザインと実装のズレに悩む夜は二度と訪れなくなるはずだ。さあ、エディタを開き、システムを再構築しよう。

タイトルとURLをコピーしました