Slide 1

Slide 1 text

Bulletproof Design System with TypeScript Bulletproof Design System with TypeScript takanorip / 2025.05.23

Slide 2

Slide 2 text

大木尊紀 / takanorip 株式会社カンム - エンジニア・デザイナー UIをエンジニアリングするのが好き。 デジタルを脱出したい。 01

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

0 デザインシステム概観 1 デザインシステムのルール守られない問題 2 TypeScriptとデザインシステム 3 コンポーネントのProps設計 4 デザイントークンの型定義活用 5 LLMによるドキュメントの自動生成

Slide 7

Slide 7 text

堅牢なデザインシステム

Slide 8

Slide 8 text

デザインシステムの定義 ちいデザシス本によると… “「デザインシステム」は一般的に、「デザインの再現性を高め、一貫した 製品体験を効率よく表現すること」を目的に導入される「ドキュメントや リソース群のこと」と説明されます。” 大塚 亜周,稲葉 志奈,金森 悠,samemaru,圓山 伊吹,植田 将基,関口 裕,8chari,後藤 拓也,小木曽 槙一,桝田 草一. ち いさくはじめるデザインシステム (p.5). Kindle 版.

Slide 9

Slide 9 text

デザインシステム = ルールセット+ドキュメント+実装

Slide 10

Slide 10 text

デザインシステムが達成したいこと 制約を整えて デザインを再現可能にすること ルールをつくるだけでは再現可能にならない。 ルールが適用されたデザインがルールどおりに実装されることが必要不可欠。

Slide 11

Slide 11 text

デザインシステムとUIライブラリの違い 「らしさの再現」が 組み込まれているかどうか プロダクトらしいデザインを再現できるようになっているかどうか。 ただコンポーネントを寄せ集めただけでは「らしく」ならない。 ボトムアップとトップダウン、両方の視点が必要

Slide 12

Slide 12 text

TOP(意思決定が必要) デザイン原則(らしさを定義したもの) ボイス&トーン スタイルガイド コンポーネント デザイントークン BOTTOM(現状の整理)

Slide 13

Slide 13 text

90%くらいのエンジニアは デザインシステムのルールを守らない (デザイナーも守らないことある)

Slide 14

Slide 14 text

B デザインシステムのことをよく理解してな3 B ドキュメントを読んでな3 B 面倒だし適当でいいだろと思ってÂ B etc...

Slide 15

Slide 15 text

堅牢なデザインシステムを 構築したいなら、

Slide 16

Slide 16 text

人間の善意に頼るのではなく 仕組みでルールを強制する

Slide 17

Slide 17 text

ルールは守られない前提で 逸脱している箇所を見つけやすくする

Slide 18

Slide 18 text

ドキュメントを更新し続ける

Slide 19

Slide 19 text

TypeScriptと デザインシステム

Slide 20

Slide 20 text

デザインシステム = デザインに制約を加える装置 TypeScript = 実装に制約を加える装置

Slide 21

Slide 21 text

TypeScript(型定義)で デザインシステムの制約を強制する

Slide 22

Slide 22 text

TypeScriptがもたらす4つの効果 6 コンポーネントの自由度を適切にコントロールす@ 6 補完やサジェストを活用す@ 6 コンパイルエラーでルール違反を見つけ@ 6 LLMの出力をサポートする

Slide 23

Slide 23 text

要素ごとに 具体例を紹介していきます

Slide 24

Slide 24 text

デザイントークンの 型定義活用

Slide 25

Slide 25 text

Style Dictionaryを活用 typescript/es6-declarations で型定義を出力する export const : export const : ; ; ColorBackgroundGray string ColorBackgroundBlue string これを利用してコンポーネントのPropsなどを自動生成できる

Slide 26

Slide 26 text

Branded Typesの活用 SpacingとRadiusなど構造が同一だが混同したくないものを区別できる type extends = & in : type = type extends = extends ? | : export type = export const : < , > { [ ] }; ; < > < , > ; < >; ; Branded T U T key U TokenType DesignToken T T TokenType Branded T DesignTokenSpacing DesignToken DesignTokenSpacing string never string string never SizeSpacingXs 'spacing' 'designToken' 'spacing'

Slide 27

Slide 27 text

Branded Typesの生成 Style Dictionaryの を利用する registerTransform import from => => StyleDictionary ; StyleDictionary. ({ type: , transitive: , name: , : ( , ) {}, : ( ) { }, }); 'style-dictionary' `value` `myTransitiveTransform` registerTransform filter transform true token options token // token.value will be resolved and transformed at this point

Slide 28

Slide 28 text

VSCode拡張をつくる Style Dictionaryで生成した型を活用してVS Code拡張などのツールを 開発すると一石二鳥 参考W V V デザイントークンを自動補完するVS Code拡張機能を開発しまし™ CSS Variables 形式のデザイントークンを補完する VS Code Extension を作 成し生産性を上げる

Slide 29

Slide 29 text

コンポーネントの Props設計

Slide 30

Slide 30 text

基本方針 Styleの上書きを許容しない CSSを書かせない 中途半端に上書きさせない。 どうしても変更したい場合は別コンポーネントを作る。 className や styles は受け取らない。 Propsでスタイルをコントロールする。

Slide 31

Slide 31 text

ubie-ui/Button

Slide 32

Slide 32 text

StyleをPropsで管理する Chakra UI V2のStyle Propsの考え方を採用。 すべてのCSSに対応する必要はなく、必要があるものだけ対応すれば良い。 // mx = margin x < = > Box mx Test Box "xxs"

Slide 33

Slide 33 text

export const : | = ... => return < = ? : ? : ... > < > ({ mx, props }) { ( style {{ : rightKey (rightKey) , : leftKey (leftKey) , }} { } { } BoxComponent ); }; Box FC PropsWithoutText PropsWithTextBody createSpacingVariableFromKey createSpacingVariableFromKey BoxComponent props children '--padding-right' '0' '--padding-left' '0'

Slide 34

Slide 34 text

CSS VariablesをTemplate Literalで管理する const = : => return export const = ?: => return ? : as ( ) { DesignTokens radius key path ; }; ( ) { { : radius (radius) , } ; }; createRadiusVariableFromKey Radius join radiusVariables Radius createRadiusVariableFromKey CSSProperties key radius `var(--${ . [ ]. . ('-')})` '--radius' '0'

Slide 35

Slide 35 text

as Propの活用 type extends = ?: : & export default function extends = ... : const = as || return ... < . > { ; . ; } . ; < . >({ , , } < >) { ; < { }> : {children} Component ; } BoxProps C React ElementType C React ReactNode React ComponentPropsWithoutRef Box C React ElementType BoxProps C Component rest as children as children rest 'div' 'div' Component BOX

Slide 36

Slide 36 text

JSDocのDocumentation機能を活用 エディタの機能を活用して アップデートを知らせる

Slide 37

Slide 37 text

StyleをPropsで管理する Chakra UI V2のStyle Propsの考え方を採用。 すべてのCSSに対応する必要はなく、必要があるものだけ対応すれば良い。 // mx = margin x < = > Box mx Test Box "xxs"

Slide 38

Slide 38 text

Figmaとの連携

Slide 39

Slide 39 text

Figmaをデザイントークンの Single Source of Truthとして扱う デザイントークンは ビジュアルとセットで管理する コード(JSONなど)をSSoTとして扱う風潮もあるが私は懐疑的。 カラーコードを見て色がわかる人がいないと扱えないのでは? Figma(デザインツール)からJSONを生成するほうが認知不可低いと考える。

Slide 40

Slide 40 text

No content

Slide 41

Slide 41 text

GitHub Actions経由でデザイントークンを書き出す できる限り自動化しておくことでデザイナーでも更新できるようにする Figma REST API の Open API Spec が公開されているので、 TypeScriptを活用して処理を実装できる https://github.com/figma/rest-api-spec import type from const = await { GetFileResponse } axios. < >(url); result.data '@figma/rest-api-spec' result get GetFileResponse // This has type GetFileResponse

Slide 42

Slide 42 text

Figma JSON (Design Tokens Format Module) GitHub Actions TypeScript, CSS Style Dictionary

Slide 43

Slide 43 text

Figma Variablesは一工夫 Figma VariablesはエンタープライズプランでないとREST API経由での 値取得ができない。 そのためコンポーネントを経由して取得するなどの工夫が必要になる。

Slide 44

Slide 44 text

Variables Variablesの値を適用したオブジェクトをコンポーネント化 コンポーネントのスタイルからトークンの値を取得

Slide 45

Slide 45 text

余談:Figma Code Connectには懐疑的 便利な機能であることは間違いないが、Figmaでデザインする段階から Code Connectほど強く実装を意識する必要があるのか、わからない。 Figmaで普通にデザインをつくりLLMを活用して開発する、くらいが ちょうどよいと思っている。

Slide 46

Slide 46 text

LLMによる ドキュメントの 自動生成

Slide 47

Slide 47 text

ドキュメントの死 = デザインシステムの死 ドキュメントが更新されなくなると 誰もデザインシステムを使わなくなる どれだけコンポーネントや便利な仕組みが追加されても ドキュメントが更新されなくなったら終わる。

Slide 48

Slide 48 text

なんでドキュメントが更新されないのか デザインシステムのドキュメントは デザイナーパートとエンジニアパートが 混在しているので運用が難しいから 理想的にはデザインシステム専門の編集者がほしい。 しかし大抵の場合そんな余裕はない。 デザインエンジニアが全部書くことになる。

Slide 49

Slide 49 text

そうだ!LLMだ! LLMなら 両方の視点から いい感じに ドキュメントを 書くことができそう

Slide 50

Slide 50 text

コメントやJSDocがLLMの役に立つ デフォルト値や用途を記述しておくといい感じにまとめてくれる。 /** * サイズ * */ @default large size?: | | ; 'large' 'medium' 'small'

Slide 51

Slide 51 text

記述するべき内容とWritingStyleを指示する ドキュメントの構成、各セクションに書く内容、だれの視点で書くのか、 などを指示するためのドキュメントを書く contents.md ## Features コンポーネントの概要を記述。 ## Props 各Propsについての解説を記述。 … 参考:個人的 AI Writing のやりかた

Slide 52

Slide 52 text

コンポーネントと指示書をLLMにわたす ドキュメントを書く対象と指示書を渡す。 普通に間違ったこと書いたりするのでレビューは必須。 @src/components/Button.tsx のドキュメントを書いてください。 FigmaのデザインはこのURL @https://www.figma.com/design/... 執筆スタイルは @rules/writing-rule.md に従ってください。

Slide 53

Slide 53 text

デザインシステムは monorepo 化したほうが良い? ドキュメント作成における LLM支援を最大化したいなら 1つのリポジトリに集約するべき しかし全てをLLMに学習させることは難しいので 与える情報をコントロールする必要がある。MCP?わからん。

Slide 54

Slide 54 text

まとめ

Slide 55

Slide 55 text

まとめ # デザイントークンの型定義を活G # コンポーネントは自由度を下げつつ必要な
 オプションを用意すh # TypeScriptでType SafeなFigma連È # ドキュメントをメンテナンスし続ける

Slide 56

Slide 56 text

Special thank to 腹筋ローラーの力を信じろ @8845musign

Slide 57

Slide 57 text

ありがとう ございました ありがとう ございました