コンポーネント指向なフレームワーク(Vue, React, Angularなど)でフロントエンドを実装する際、どのレベルでコンポーネントを分ければ良いのか悩むことがよくあります...。その際に参考となるものが欲しかったので、UIデザインシステムの代表例でもあるAtomicDesignを最近学習しました。自分なりの理解/実装方法を備忘録として記事にしましたので、同志のお役に立てると幸いです。あくまで個人的にしっくりきた考えのもと作成した記事ですので、ご了承ください❗️
AtomicDesignとは
WebデザイナーのBrad Frost氏によって提唱されたデザインシステムです。
「小さい要素を組み合わせることでUIを作成していこう」という考え方でUIを構築するのが特徴です。小さい単位でコンポーネントをたくさん用意していおいて、必要なところで随時利用するという流れで実装していきます。これにより、再利用可能でメンテナンス性の高い実装をすることができます。アトミックデザイン、なんか必殺技みたいでかっこいいですよね。
AtomicDesignを構成する5つのパーツ
AtomicDesignの最大の特徴として、5つのパーツが用意されます。
小さい単位から順に、Atoms
、Molecules
、Organisms
、Templates
、Pages
と呼ばれます。それぞれの単位は基本的に、その単位よりレベルの低い単位を構成して作られます。
※出典:Atomic Design by Brad Frost
以下では、それぞれのレベルの定義と、実装する際に気を付けるポイントを自分なりにまとめました。
Atoms(原子)
AtomicDesignにおける最小単位です。ボタン、アイコン、リンクなどの「それ以上分解できないもの」がAtoms
にあたります。
Atoms
を実装する上で意識するポイントは以下です。
- 1つのタグのみで完結する(
a
,input
,button
,p
など) - 特定の文言を表示しない(UIの知識を保持しない)
- APIは実行しない(アプリケーションの知識を保持しない)
- 表示したい文言や、指定する属性などは
props
で受け取り、汎用性の高いものにする -
props
を利用して親からデータを受け取る -
emit
を利用して親のイベントを発火する
Molecules(分子)
Atomの組み合わせによって意味を持つ要素です。
Molecules
を実装する上で意識するポイントは以下です。
-
Atoms
を組み合わせて意味を成す最小限の集合(入力フォームと、エラーメッセージが表示される領域のセットなど) - 特定の文言を表示してもよい(UIの知識を保持してもよい)
- APIは実行しない(アプリケーションの知識を保持しない)
- 一応機能するが、単体では成立しない
-
props
を利用して親からデータを受け取る -
emit
を利用して親のイベントを発火する
Organisms(有機体)
Atoms
またはMolecules
の組み合わせよって作成されたヤツです。
Organisms
を実装する上で意識するポイントは以下です。
- 特定の文言を表示してもよい(UIの知識を保持してもよい)
- APIを実行をしてもよい(アプリケーションの知識を保持してもよい)
- それ単体で機能する / そのまま別のTemplateに置くだけでも成立する
-
props
は基本書かない:単体で成立させる為
Templates(テンプレート)
Organisms
の位置を定義したワイヤーフレームみたいなヤツです。
Templates
を実装する上で意識するポイントは以下です。
-
Organism
、Molecules
、Atom
を組み合わせてページの見た目を作成する - これを見ただけでどんな感じのページなのかが分かる必要がある
- 特定の文言を表示てもよい(UIの知識を保持してもよい)
- APIを実行をしてもよい(アプリケーションの知識を保持してもよい)
- 画面毎に
Templates
を用意して、ルーティングではコレを出し分ける(人によって異なるのですが僕はコレがやりやすいと思います) - 基本的に
Molecules
とAtoms
は使わない
Pages(ページ)
AtomicDesignでのUI開発における最終形態で、実際にユーザーに表示される画面です。Templates
との違いは、実際に表示される画像やユーザー毎のデータが表示されているかどうかの違いです。個人的には、Templates
とPages
は大体同じものという認識でもよさそうな気がします。実装を分ける必要もあまり無いと思います。
AtomicDesignを採用するメリット・デメリット
メリット
- 作成したコンポーネントを、別アプリで同様のレイアウトを作成する際に再利用することができる
- それぞれのコンポーネントの役割が明確になる
- メンテナンスしやすい
- 複数画面で使用されている小さい要素に対して修正が入った際に、修正箇所が縮小される(ボタンの色修正とか)
- 一貫性の向上
- チーム全体で共通の考えの元コンポーネント分割ができることによる
デメリット
- 実装が難しい
- 汎用性を持たせるのは難易度が高い
- AtomicDesignの考え方のズレが生まれやすいので、どの粒度で分けるかで混乱を生みやすい。「このプロジェクトではこれでいこう!」などの認識の共有が必要
実装例(Vue.js)
AtomicDesignな実装を取り入れたプロジェクトでの経験と、AtomicDesignを学習して学んだことを元にVue3でシンプルな画面を実装してみました。CSSフレームワークにはTailwindCSSを使用しています(Tailwind...?という方はこちらの記事でTailwindについて紹介していますので、是非ご覧ください!)。
コードはこちらのリポジトリに格納されています。
探り探りの実装なので、「この方が良くない...?」等ありましたら、是非コメントお願いします❗️
src/
配下のディレクトリ構成は以下のようにしました。
src
├── App.vue
├── components
│ ├── atoms
│ │ ├── AtomButton.vue
│ │ ├── AtomImage.vue
│ │ ├── AtomLink.vue
│ │ ├── AtomText.vue
│ │ └── AtomTitle.vue
│ ├── molecules
│ │ ├── MoleculeCard.vue
│ │ ├── MoleculeHeaderLinks.vue
│ │ └── MoleculeHeaderTitle.vue
│ ├── organisms
│ │ ├── OrganismCards.vue
│ │ ├── OrganismFooter.vue
│ │ └── OrganismHeader.vue
│ └── templates
│ └── TemplateHome.vue
Atoms
ならAtom~.vue
、Molecules
ならMolecule~.vue
、Organisms
ならOrganism~.vue
、Templates
ならTemplate~.vue
とった感じでそれぞれのコンポーネントファイル名を付けることが良さそうです。使用される際に、そのコンポーネントがどの単位のものなのかが明確になるのでオススメです(特にAtoms
とMolecules
が入り混じるOrganisms
内が見やすくなります)。
最後まで読んでいただきありがとうございました!