Governance & Đóng gópGovernance & Contribution
Thuộc bộ kiến thức Design System Roadmap.
Tổng quan
Một design system là một sản phẩm dùng chung. Ngay khi có nhiều hơn một team phụ thuộc vào nó, mỗi thay đổi đều có cái giá phải trả bởi những người không có mặt lúc quyết định được đưa ra — một token bị đổi tên làm hỏng cả chục màn hình, một variant component mới âm thầm lệch khỏi component đã có, một “fix nhanh” được merge mà không qua review trở thành khuôn mẫu để mọi người copy theo. Governance là tập hợp các quy tắc quyết định ai được phép thay đổi cái gì, những thay đổi đó được đề xuất và review ra sao, và điều gì xảy ra khi có người không đồng ý với quyết định cuối cùng. Contribution (đóng góp) là phần cơ chế thực tế, hàng ngày — CONTRIBUTING.md, PR template, quy ước commit, linting — biến governance từ một tài liệu chính sách không ai đọc thành thứ thực sự dùng được.
Không có governance, một design system thường thất bại theo một trong hai hướng trái ngược nhau. Nếu hoàn toàn không có ai sở hữu (ownership), mỗi người chạm vào code sẽ tự đưa ra phán đoán riêng, và hệ thống vỡ vụn thành các “đảo” không nhất quán, không còn giống một “hệ thống” nữa. Nếu có ownership nhưng không có con đường nhẹ nhàng nào để team bên ngoài đóng góp, hệ thống sẽ trì trệ — core team trở thành nút thắt cổ chai, backlog phình to, và các product team bắt đầu fork component ở local chỉ để kịp deadline. Governance tốt là sự cân bằng giữa hai kiểu thất bại này: đủ kiểm soát tập trung để giữ hệ thống mạch lạc, đủ cởi mở để các team phụ thuộc vào nó cũng có thể góp phần phát triển nó.
Bài này sẽ đi qua các governance model, decision rights (quyền quyết định), contribution guidelines, PR template, quy ước commit/code style, và cách xử lý những bất đồng không thể tránh khỏi giữa team design system và các product team mà nó phục vụ.
Kiến thức nền tảng
Vì sao governance quan trọng
Một component library là code, nhưng một design system còn là một hợp đồng (contract): người dùng xây sản phẩm dựa trên giả định rằng Button sẽ hoạt động nhất quán ở mọi nơi, rằng một spacing token mang cùng một ý nghĩa trên mọi màn hình, rằng một breaking change sẽ được cảnh báo trước khi nó làm hỏng build của họ. Governance là thứ giữ cho hợp đồng đó còn nguyên vẹn khi số lượng người đóng góp tăng lên. Cụ thể, governance trả lời bốn câu hỏi liên tục xuất hiện:
- Ai được phép duyệt một thay đổi visual hay token ảnh hưởng đến tất cả consumer cùng lúc?
- Ai được phép thêm một component hoàn toàn mới vào shared library, và với tiêu chuẩn nào?
- Một breaking change được thông báo, lên lịch, và rollout như thế nào?
- Phương án dự phòng khi cần fix một lỗi chính tả trong docs hay một fix nhỏ cần lên trong ngày là gì?
Nếu những câu hỏi này không có câu trả lời sẵn, mỗi thay đổi sẽ trở thành một cuộc tranh luận — chính là nút thắt cổ chai mà các team cố tránh bằng cách tự tạo ra các workaround tùy tiện.
Căng thẳng cốt lõi: consistency vs. velocity
Mọi governance model đều nằm ở đâu đó trên một dải quang phổ giữa hai lực:
- Consistency (tính nhất quán) — một nhóm nhỏ người có đầy đủ context và thẩm quyền design review mọi thứ, nên chất lượng và sự mạch lạc luôn cao, nhưng thông lượng bị giới hạn bởi băng thông của nhóm đó.
- Velocity (tốc độ) — nhiều người ở nhiều team có thể đóng góp trực tiếp, nên backlog di chuyển nhanh hơn, nhưng tính mạch lạc phụ thuộc hoàn toàn vào kỷ luật của quy trình review.
Không có một điểm “đúng tuyệt đối” nào trên quang phổ này — nó phụ thuộc vào quy mô tổ chức, độ trưởng thành của design system, và mức độ tin tưởng giữa core team và các product team. Ba model dưới đây là những cách phổ biến mà các tổ chức dùng để giải quyết căng thẳng này.
Khái niệm chính
So sánh các governance model
| Model | Cách hoạt động | Ưu điểm | Nhược điểm | Phù hợp nhất với |
|---|---|---|---|---|
| Centralized (tập trung) | Một core team duy nhất thiết kế, xây dựng, review, và merge mọi thay đổi. Product team chỉ gửi yêu cầu chứ không commit trực tiếp. | Tính nhất quán cao nhất; tiêu chuẩn chất lượng design/API cao; single source of truth dễ suy luận. | Core team trở thành bottleneck khi số consumer tăng; backlog chất đống; product team có thể fork component vì bức xúc. | Tổ chức nhỏ, design system giai đoạn đầu, hoặc hệ thống có ít team consumer (khoảng dưới 5–10 team). |
| Federated / distributed (phân tán) | Product team có thể đề xuất và thậm chí tự implement thay đổi (variant mới, component mới), nhưng core team giữ quyền review và merge, đồng thời áp một ngưỡng đóng góp (test, docs, accessibility, design review sign-off). | Vượt qua giới hạn năng lực của core team; product team cần gấp có thể tự xây thay vì chờ đợi; core team tập trung vào review + kiến trúc thay vì tự xây mọi thứ. | Đòi hỏi kỷ luật review mạnh, được tài liệu hóa rõ ràng — thiếu nó, chất lượng dao động thất thường theo từng đóng góp; core team vẫn phải đầu tư thời gian thật cho review, mentoring contributor, và giữ chuẩn. | Tổ chức vừa và lớn với design system đã ổn định và nhiều product team trưởng thành sẵn sàng đầu tư thời gian engineering vào code dùng chung. |
| Open contribution (mở) | Bất kỳ ai trong tổ chức (thậm chí cả contributor bên ngoài, với hệ thống mã nguồn mở) đều có thể mở đề xuất hoặc PR. Core team đóng vai trò curator: triage, chấp nhận/từ chối, merge. | Tối đa hóa số người có thể đề xuất ý tưởng và fix; phù hợp với design system mã nguồn mở (ví dụ các thư viện do cộng đồng dẫn dắt) hoặc tổ chức rất lớn. | Đòi hỏi đầu tư tooling nặng nhất (template, automated check, quy trình RFC) để kiểm soát nhiễu; thiếu curation mạnh, chất lượng và định hướng dễ trôi dạt; từ chối đề xuất chậm có thể gây căng thẳng chính trị. | Tổ chức lớn với hàng chục team consumer, hoặc design system mã nguồn mở thực sự có cộng đồng contributor bên ngoài. |
Hầu hết hệ thống thực tế không thuần túy theo một model — chúng tiến hóa theo thời gian. Một design system thường bắt đầu ở dạng centralized khi còn nhỏ và chưa ổn định, chuyển sang federated khi nhiều product team phụ thuộc vào nó và muốn tốc độ nhanh hơn khả năng review của core team, và chỉ áp dụng cơ chế open-contribution (RFC, bảng đề xuất công khai) khi hệ thống đã đủ trưởng thành để “hình dạng” của nó ổn định và nhu cầu chính chỉ còn là mở rộng dần dần.
Decision rights: ai duyệt cái gì
Ngay cả trong một governance model duy nhất, không phải loại thay đổi nào cũng nên yêu cầu cùng một người duyệt. Việc ánh xạ loại thay đổi tới người phê duyệt ngay từ đầu giúp tránh phải tranh luận lại câu hỏi này mỗi khi có PR mở ra.
| Loại thay đổi | Người duyệt thường thấy | Vì sao |
|---|---|---|
| Thay đổi visual hoặc token (màu sắc, spacing, typography scale) | Design lead của design system + core team engineering review | Ảnh hưởng thị giác tới mọi consumer; cần cả phán đoán design lẫn đánh giá blast radius (component/token nào đang dùng nó). |
| Đề xuất component mới | Core team (design + engineering) qua quy trình RFC/proposal, thường co-design cùng product team | Component mới là bề mặt tốn kém nhất để bảo trì lâu dài — ngưỡng đánh giá nên là “cái này có thuộc về shared system không,” chứ không chỉ “code chạy được không.” |
| Variant mới trên component đã có | Core team engineering, design review nhẹ hơn nếu có thay đổi visual | Rủi ro thấp hơn component hoàn toàn mới; vẫn cần tránh lặp lại logic đã tồn tại ở nơi khác trong hệ thống. |
| Breaking API change (đổi tên prop, xóa component, đổi hành vi mặc định) | Core team + sign-off tường minh theo quy trình deprecation/migration đã định | Breaking change lan tới codebase của mọi consumer; phải được lên lịch, gắn version (xem semver), và thông báo kèm migration path. |
| Sửa lỗi chính tả / typo trong docs / ví dụ hỏng | Bất kỳ contributor nào, fast-track, một reviewer là đủ | Blast radius bằng không với production consumer; gác cổng việc này chỉ làm nản lòng đóng góp thiện chí. |
| Bug fix (không breaking) | Core team engineering review, không cần design sign-off trừ khi hành vi visual thay đổi | Thuần túy sửa lỗi; nên xử lý ở tốc độ code review bình thường. |
| Override styling một lần cho campaign của một team | Product team tự chịu trách nhiệm ở local; core team không phải người duyệt, nhưng áp dụng quy trình ngoại lệ ở phần dưới | Nếu thực sự là one-off thì vốn không nên nằm trong shared system; xem phần “Xử lý bất đồng.” |
Việc công bố một bảng như thế này trong tài liệu của design system (không chỉ trong bài note này) loại bỏ phần lớn ma sát mà nếu không sẽ bị tranh cãi lại từng PR một.
Contribution guidelines (CONTRIBUTING.md)
CONTRIBUTING.md là phần đối ứng vận hành của governance model — nó nói cho contributor biết chính xác phải làm gì, theo thứ tự, trước khi viết code. Một CONTRIBUTING.md tốt bao gồm:
1. Cách đề xuất component mới. Yêu cầu một proposal nhẹ nhàng trước khi viết code: vấn đề gì đang được giải quyết, có component nào đã đáp ứng 80% nhu cầu chưa (composition thay vì tạo component mới), API trông như thế nào, có cần token mới không. Nhiều hệ thống yêu cầu điều này dưới dạng issue hoặc RFC template, được core team review trước khi bắt đầu implement — điều này tránh việc ai đó mất cả tuần xây một component rồi bị từ chối vì trùng lặp chức năng đã có.
2. Khi nào cần design review, khi nào chỉ cần code review. Một quy tắc ngón tay cái hữu ích: nếu thay đổi ảnh hưởng đến bất cứ thứ gì người dùng có thể thấy hoặc cảm nhận (màu sắc, spacing, chuyển động, nội dung, một trạng thái visual mới) thì cần design review; nếu thuần túy nội bộ (refactor, hiệu năng, type, test coverage) thì code review là đủ. Nói rõ điều này để contributor không phải đoán, và reviewer không phải giải thích lại trong từng PR.
3. Quy trình yêu cầu thêm token thay vì hardcode một giá trị. Đây là một trong những cách phổ biến nhất khiến design system bị xói mòn từ bên trong — một contributor cần “thêm một sắc xanh nữa” hay “chỉ cần thêm 2px padding” và hardcode luôn thay vì chờ token request được review. CONTRIBUTING.md nên nói rõ: tìm token hiện có trước (phần lớn nhu cầu one-off thực ra đã được đáp ứng bởi một token có sẵn nhưng bị dùng sai ở nơi khác), nếu không có token nào phù hợp, mở issue yêu cầu token kèm use case và nơi có thể áp dụng thêm, và không bao giờ merge một component hardcode giá trị màu/spacing/font thô lẽ ra phải là token. Coi token request là một quy trình hạng nhất, nhanh chóng (không phải một cuộc hành trình nhiều tuần) là điều giữ cho việc hardcode không trở thành con đường ít trở ngại nhất.
4. Setup, testing, và definition of done. Cách setup môi trường local, cách chạy test suite và visual regression check, “done” nghĩa là gì cho một PR (test, mục Storybook/docs, changelog entry, accessibility check) trước khi nó thậm chí được xem xét review.
PR template
PR template biến “nhớ đính kèm screenshot và kiểm tra accessibility nhé” thành thứ được tooling ép buộc bằng sự hiện diện, chứ không phải bằng trí nhớ. Ví dụ thực tế cho một repo design system:
## What changed (Đã thay đổi gì)
<!-- Một hoặc hai câu: PR này thêm, sửa, hay thay đổi gì? -->
## Why (Vì sao)
<!-- Link tới issue/RFC/design file. Vấn đề gì được giải quyết, hay yêu cầu
nào được đáp ứng? Nếu là component/token mới, link tới proposal/approval. -->
## Screenshots / before-after
<!-- Bắt buộc với mọi thay đổi visual. Dán screenshot before/after hoặc một
đoạn ghi hình ngắn. Với component mới, hiển thị tất cả variant và
trạng thái đã được tài liệu hóa (default, hover, focus, disabled, error). -->
| Before | After |
|--------|-------|
| | |
## Accessibility checklist
- [ ] Color contrast đạt WCAG AA (4.5:1 cho text, 3:1 cho UI component) ở mọi trạng thái đã tài liệu hóa
- [ ] Component điều hướng được bằng bàn phím (tab order, focus hiển thị, Enter/Space/Esc hoạt động đúng)
- [ ] Dùng đúng semantic HTML / ARIA role; screen reader thông báo được các thay đổi trạng thái
- [ ] Hoạt động tốt khi resize text lên 200% và với `prefers-reduced-motion`
- [ ] Automated a11y check (ví dụ axe) pass trong CI
## Breaking change?
- [ ] Có — mô tả migration path bên dưới và xác nhận sẽ bump major version
- [ ] Không
## Checklist
- [ ] Đã link tới design file / proposal / issue
- [ ] Đã thêm hoặc cập nhật test
- [ ] Đã thêm hoặc cập nhật mục Storybook / docs
- [ ] Đã thêm changelog entry
- [ ] Không hardcode màu/spacing/font — dùng token hiện có hoặc token vừa được duyệt
Yêu cầu bắt buộc điền phần “Breaking change?” và accessibility — được ép buộc bởi PR template và, lý tưởng nhất, một CI check fail nếu checklist chưa được đụng tới — là thứ thực sự giúp những mục này được kiểm tra một cách nhất quán, thay vì trông chờ vào trí nhớ của reviewer.
Commit guidelines và code style
Git history của một design system được đọc nhiều hơn hẳn so với hầu hết repo ứng dụng thông thường, vì consumer dùng nó để hiểu vì sao một API thay đổi, và tooling release (changelog, semantic version bump) thường được generate trực tiếp từ commit message. Hai thực hành sau mang trọng lượng không tương xứng:
- Conventional Commits. Một định dạng commit có cấu trúc (
feat:,fix:,docs:,refactor:,feat!:hoặc footerBREAKING CHANGE:cho breaking change) cho phép tooling tự động generate changelog và thậm chí tự xác định semantic version tiếp theo (fix:ngụ ý patch bump,feat:ngụ ý minor bump, bất cứ gì đánh dấu breaking ngụ ý major bump). Chủ đề này được nói sâu hơn trong Versioning & Release Management, nhưng kỷ luật này bắt đầu từ commit message, không phải từ lúc release. - Automated linting và formatting. Tranh cãi về style (tab vs. space, thứ tự import, quy ước đặt tên prop) là lãng phí thời gian reviewer thuần túy trong một shared library nơi hàng chục contributor cùng chạm vào code. Ép buộc formatting (ví dụ Prettier) và linting (ESLint/Stylelint hoặc tương đương) trong CI để một PR đơn giản là không thể merge nếu vi phạm style — điều này loại bỏ hoàn toàn tranh cãi này khỏi code review và giữ cho review tập trung vào nội dung thực chất: thiết kế API, accessibility, và liệu thay đổi này có thuộc về hệ thống hay không.
Kết hợp lại, quy ước commit và ép buộc style tự động thu gọn cuộc trò chuyện review về hai điều thực sự cần phán đoán con người: đây có phải thay đổi đúng không, và nó có chính xác không.
Xử lý bất đồng và ngoại lệ
Ngay cả với decision rights rõ ràng, sớm muộn cũng có một product team muốn thứ gì đó mà design system không hỗ trợ — một màu one-off cho chiến dịch marketing, một variant component chỉ có ý nghĩa với sản phẩm của họ, một deadline không thể chờ chu kỳ review tiếp theo của core team. Governance phải có câu trả lời tường minh cho việc này, nếu không các team sẽ đơn giản là override token ở local và âm thầm lệch hướng — chính là sự phân mảnh mà governance tồn tại để ngăn chặn.
Một quy trình escalation/exception khả thi thường có ba tầng:
- Compose trước. Trước khi cấp một ngoại lệ, kiểm tra xem nhu cầu có thể được đáp ứng bằng cách kết hợp (compose) các component/token hiện có theo cách khác hay không. Phần lớn yêu cầu “chúng tôi cần thứ gì đó custom” thực ra có thể giải quyết bằng hệ thống hiện có nếu dùng đúng cách — đây nên là phản hồi đầu tiên của core team, không phải là một con dấu chấp thuận tự động.
- Override có phạm vi, giới hạn thời gian, có dấu vết rõ ràng. Nếu một nhu cầu one-off thực sự chính đáng (ví dụ, một chiến dịch marketing duy nhất với deadline cứng từ bên ngoài), cho phép override cục bộ, nhưng yêu cầu nó phải tường minh, được tài liệu hóa, và có ngày hết hạn — ví dụ, một override token có phạm vi cục bộ được commit kèm comment link tới ticket ngoại lệ và ngày kết thúc, thay vì một giá trị hardcode âm thầm. Team design system nên được thông báo để ngoại lệ này hiện diện rõ ràng chứ không âm thầm biến thành “cách chúng ta vẫn luôn làm.”
- Nâng cấp thành proposal chính thức. Nếu cùng một yêu cầu ngoại lệ lặp lại — nhiều team cùng xin một variant, hoặc cùng một nhu cầu campaign lặp lại quý này qua quý khác — đó là tín hiệu cho thấy nó nên trở thành một proposal thật sự cho token hoặc component mới, chứ không phải một ngoại lệ vĩnh viễn. Theo dõi các yêu cầu ngoại lệ lặp lại như đầu vào cho roadmap của hệ thống.
Nguyên tắc cốt lõi: một quy trình exception nên khiến con đường được cho phép dễ đi hơn việc âm thầm fork, và nó nên đưa các ngoại lệ lặp lại quay trở lại hệ thống thay vì để chúng chất đống thành nợ kỹ thuật vĩnh viễn. Vấn đề team và sức khỏe cộng đồng xung quanh quy trình này được nói thêm trong Adoption, Community & Support; kiến trúc component và token nền tảng mà những quyết định này áp dụng lên được nói trong Building a Design System.
Best Practices
- Viết bảng decision-rights và công bố cùng CONTRIBUTING.md — phần lớn ma sát governance đến từ sự mơ hồ về việc ai duyệt cái gì, chứ không phải bất đồng về nội dung quy tắc.
- Chọn governance model khớp với độ trưởng thành thực tế của team, không phải khớp với khát vọng. Một tổ chức năm người chạy quy trình RFC “open contribution” là over-engineer; một tổ chức năm mươi team vẫn yêu cầu mọi ý tưởng component đi qua một designer duy nhất là dưới quy mô. Xem lại model khi tổ chức phát triển.
- Làm cho con đường nhanh nhanh hơn cả workaround. Nếu yêu cầu thêm token mất ba tuần, contributor sẽ hardcode giá trị thay vì chờ. Đòn bẩy lớn nhất để giữ hệ thống nhất quán là làm cho cách làm “đúng” cũng là con đường ít trở ngại nhất.
- Tự động hóa những gì không bao giờ nên là tranh cãi giữa người với người. Formatting, linting, accessibility smoke test, và tạo changelog nên chạy trong CI, không phải trong đầu reviewer.
- Yêu cầu bằng chứng trong PR, không chỉ mô tả suông. Screenshot, accessibility checklist, và cờ breaking-change tường minh bắt lỗi trước khi merge đáng tin cậy hơn nhiều so với trí nhớ của reviewer.
- Làm cho ngoại lệ hiển thị và có giới hạn thời gian. Một override cục bộ âm thầm không thể phân biệt được với sự phân mảnh cho đến khi bị phát hiện nhiều tháng sau; một ngoại lệ được tài liệu hóa, có ngày hết hạn, gắn link ticket là quản lý được và cho core team một vòng phản hồi.
- Xem lại chính governance model theo định kỳ. Đối xử với nó như bất kỳ phần nào khác của hệ thống — nếu core team liên tục là bottleneck, hoặc chất lượng rõ ràng đang xuống cấp vì open contribution quá mức, đó là tín hiệu để chuyển model, chứ không chỉ là cố gắng làm việc chăm chỉ hơn trong model hiện tại.
Tài liệu tham khảo
Part of the Design System Roadmap knowledge base.
Overview
A design system is a shared product. The moment more than one team relies on it, every change carries a cost that is paid by people who were not in the room when the decision was made — a renamed token breaks a dozen screens, a new component variant silently diverges from an existing one, a “quick fix” merged without review becomes the pattern everyone copies. Governance is the set of rules that decides who can make which changes, how those changes get proposed and reviewed, and what happens when someone disagrees with the outcome. Contribution is the practical, day-to-day machinery — CONTRIBUTING.md, PR templates, commit conventions, linting — that makes governance actually usable instead of a policy document nobody reads.
Without governance a design system tends to fail in one of two opposite directions. If there is no ownership at all, everyone who touches the code makes their own judgment call, and the system fragments into inconsistent islands that no longer resemble a “system.” If ownership exists but there is no lightweight path for outside teams to contribute, the system stagnates — the core team becomes a bottleneck, backlogs grow, and product teams start forking components locally just to ship on time. Good governance is the balance between these two failure modes: enough central control to keep the system coherent, enough openness that teams who depend on it can also help grow it.
This note covers governance models, decision rights, contribution guidelines, PR templates, commit/code-style conventions, and how to handle the inevitable disagreements between a design system team and the product teams it serves.
Fundamentals
Why governance matters
A component library is code, but a design system is also a contract: consumers build products on the assumption that a Button behaves consistently everywhere, that a spacing token means the same thing in every screen, that a breaking change will be flagged before it breaks their build. Governance is what keeps that contract intact as the number of contributors grows. Concretely, governance answers four questions that come up constantly:
- Who can approve a visual or token change that affects every consumer at once?
- Who can add a brand-new component to the shared library, and under what bar?
- How is a breaking change communicated, scheduled, and rolled out?
- What is the fallback when a documentation typo or trivial fix needs to land same-day?
If these questions don’t have standing answers, every change becomes a debate, which is exactly the bottleneck teams try to avoid by adopting ad-hoc workarounds.
The core tension: consistency vs. velocity
Every governance model sits somewhere on a spectrum between two forces:
- Consistency — a small group of people with full context and design authority reviews everything, so quality and coherence stay high, but throughput is capped by that group’s bandwidth.
- Velocity — many people across many teams can contribute directly, so the backlog moves faster, but coherence depends entirely on the discipline of the review process.
There is no universally “correct” point on this spectrum — it depends on organization size, the maturity of the design system, and how much trust exists between the core team and product teams. The three models below are the common ways organizations resolve this tension.
Key Concepts
Governance models compared
| Model | How it works | Pros | Cons | Best fit |
|---|---|---|---|---|
| Centralized | A single core team designs, builds, reviews, and merges every change. Product teams file requests but do not commit directly. | Highest consistency; strong design/API quality bar; single source of truth is easy to reason about. | Core team becomes a bottleneck as consumers grow; backlog piles up; product teams may fork components out of frustration. | Small organizations, early-stage design systems, or systems with a small number of consumer teams (roughly under 5–10 teams). |
| Federated / distributed | Product teams can propose and even implement changes (new variants, components), but a core team retains review and merge authority, and enforces a contribution bar (tests, docs, accessibility, design review sign-off). | Scales past the core team’s own capacity; product teams that need something urgently can build it themselves instead of waiting; core team focuses on review + architecture instead of building everything. | Requires strong, well-documented review discipline — without it, quality varies wildly per contribution; core team still has to invest real time in reviews, mentoring contributors, and enforcing standards. | Mid-to-large organizations with an established design system and multiple mature product teams willing to invest engineering time in shared code. |
| Open contribution | Anyone in the organization (or even external contributors, for open-source systems) can open a proposal or PR. The core team curates: triage, accept/reject, merge. | Maximizes the number of people who can surface ideas and fixes; good for open-source design systems (e.g. community-driven libraries) or very large organizations. | Requires the heaviest tooling investment (templates, automated checks, RFC process) to keep noise manageable; without strong curation, quality and direction drift; slow to reject proposals can create political friction. | Large organizations with dozens of consumer teams, or genuinely open-source design systems with an external contributor base. |
Most real systems are not purely one model — they evolve. A design system commonly starts centralized while it’s small and unstable, moves to federated once several product teams depend on it and want to move faster than the core team can review, and only adopts open-contribution mechanics (RFCs, public proposal boards) once it’s mature enough that the “shape” of the system is stable and the main need is incremental extension.
Decision rights: who approves what
Even inside a single governance model, not every kind of change should require the same approver. Mapping change type to approver up front avoids re-litigating the question every time a PR is opened.
| Type of change | Typical approver | Why |
|---|---|---|
| Visual or token change (color, spacing, typography scale) | Design system design lead + core team engineering review | Affects every consumer visually; needs both design judgment and an audit of blast radius (which components/tokens consume it). |
| New component proposal | Core team (design + engineering) via an RFC/proposal process, often with product team co-design | New components are the highest-cost surface to maintain long-term — the bar should be “does this belong in the shared system,” not just “does the code work.” |
| New component variant on an existing component | Core team engineering, lighter design review if visual | Lower risk than a brand-new component; still needs to avoid duplicating logic that exists elsewhere in the system. |
| Breaking API change (renamed prop, removed component, changed default behavior) | Core team + explicit sign-off from a defined deprecation/migration process | Breaking changes ripple to every consumer’s codebase; must be scheduled, versioned (see semver), and communicated with a migration path. |
| Documentation fix / typo / broken example | Any contributor, fast-tracked, single reviewer | Zero blast radius on production consumers; gatekeeping this discourages good-faith contribution. |
| Bug fix (non-breaking) | Core team engineering review, no design sign-off needed unless visual behavior changes | Purely corrective; should move at normal code-review speed. |
| One-off styling override for a single team’s campaign | Product team owns it locally; core team is not the approver, but the exception process below applies | Doesn’t belong in the shared system at all if it’s truly one-off; see “Handling disagreement.” |
Publishing a table like this in the design system’s documentation (not just this note) removes a large share of the friction that otherwise gets litigated PR by PR.
Contribution guidelines (CONTRIBUTING.md)
A CONTRIBUTING.md is the operational counterpart to the governance model — it tells a contributor exactly what to do, in order, before they write code. A good one covers:
1. How to propose a new component. Require a lightweight proposal before code: what problem does it solve, does an existing component already cover 80% of the need (composition over new components), what does the API look like, does it need new tokens. Many systems require this as an issue or RFC template, reviewed by the core team before implementation starts — this avoids someone spending a week building a component that gets rejected for duplicating existing functionality.
2. When a change needs design review vs. only code review. A useful rule of thumb: if the change affects anything a user can see or perceive (color, spacing, motion, copy, a new visual state) it needs design review; if it’s purely internal (refactor, performance, types, test coverage) code review is sufficient. State this explicitly so contributors aren’t guessing, and so reviewers don’t have to explain it in every PR.
3. The process for requesting a new token instead of hardcoding a value. This is one of the most common ways design systems erode from the inside — a contributor needs “one more shade of blue” or “just 2px more padding” and hardcodes it rather than waiting for a token request to be reviewed. CONTRIBUTING.md should spell out: search existing tokens first (most one-off needs are actually covered by an existing token used incorrectly elsewhere), if no token fits, open a token-request issue with the use case and where else it might apply, and never merge a component that hardcodes a raw color/spacing/font value that should be a token. Treating token requests as a first-class, fast process (not a multi-week ordeal) is what keeps hardcoding from becoming the path of least resistance.
4. Setup, testing, and definition of done. Local dev setup, how to run the test suite and visual regression checks, what “done” means for a PR (tests, docs/Storybook entry, changelog entry, accessibility check) before it can be reviewed at all.
PR template
A PR template turns “please remember to include screenshots and check accessibility” into something the tooling enforces by presence, not memory. A practical example for a design system repository:
## What changed
<!-- One or two sentences: what does this PR add, fix, or change? -->
## Why
<!-- Link to the issue/RFC/design file. What problem does this solve, or what
request does it satisfy? If this is a new component or token, link the
proposal/approval. -->
## Screenshots / before-after
<!-- Required for any visual change. Paste before/after screenshots or a
short recording. For a new component, show all documented variants
and states (default, hover, focus, disabled, error). -->
| Before | After |
|--------|-------|
| | |
## Accessibility checklist
- [ ] Color contrast meets WCAG AA (4.5:1 text, 3:1 UI components) at all documented states
- [ ] Component is keyboard-navigable (tab order, focus visible, Enter/Space/Esc behave as expected)
- [ ] Correct semantic HTML / ARIA roles used; screen reader announces state changes
- [ ] Works with text resized to 200% and with `prefers-reduced-motion`
- [ ] Automated a11y checks (e.g. axe) pass in CI
## Breaking change?
- [ ] Yes — describe the migration path below and confirm a major version bump
- [ ] No
## Checklist
- [ ] Linked to design file / proposal / issue
- [ ] Tests added or updated
- [ ] Storybook / docs entry added or updated
- [ ] Changelog entry added
- [ ] No hardcoded colors/spacing/fonts — uses existing or newly-approved tokens
Requiring the “Breaking change?” and accessibility sections to be filled in — enforced by a PR template and, ideally, a CI check that fails if the checklist is untouched — is what actually gets these things checked consistently, rather than left to reviewer memory.
Commit guidelines and code style
A design system’s git history is read far more often than most application repositories’, because consumers use it to understand why an API changed, and release tooling (changelogs, semantic version bumps) is frequently generated directly from commit messages. Two practices carry disproportionate weight here:
- Conventional Commits. A structured commit format (
feat:,fix:,docs:,refactor:,feat!:or aBREAKING CHANGE:footer for breaking changes) lets tooling auto-generate changelogs and even auto-determine the next semantic version (afix:implies a patch bump,feat:a minor bump, anything marked breaking implies a major bump). This is covered in more depth in Versioning & Release Management, but the discipline starts at the commit message, not at release time. - Automated linting and formatting. Style debates (tabs vs. spaces, import order, prop naming conventions) are a pure waste of reviewer time in a shared library where dozens of contributors touch the code. Enforce formatting (e.g. Prettier) and linting (ESLint/Stylelint or equivalents) in CI so that a PR simply cannot be merged with a style violation — this removes the debate from code review entirely and keeps review focused on substance: API design, accessibility, and whether the change belongs in the system at all.
Together, commit conventions and automated style enforcement reduce the review conversation to the two things that actually require human judgment: is this the right change, and is it correct.
Handling disagreement and exceptions
Even with clear decision rights, a product team will eventually want something the design system does not support — a one-off color for a marketing campaign, a component variant that only makes sense for their product, a deadline that can’t wait for the next core-team review cycle. Governance has to include an explicit answer for this, or teams will simply override tokens locally and quietly diverge, which is exactly the fragmentation governance exists to prevent.
A workable escalation/exception process typically has three tiers:
- Compose first. Before granting an exception, check whether the need can be met by composing existing components/tokens differently. Most “we need something custom” requests are actually solvable with the existing system used correctly — this is the core team’s first response, not a rubber stamp.
- Time-boxed, scoped override, with a paper trail. If a genuine one-off is justified (e.g., a single marketing campaign with a hard external deadline), allow a local override, but require it to be explicit, documented, and expiring — for example, a locally-scoped token override committed with a comment linking to the exception ticket and an end date, rather than a silently hardcoded value. The design system team should be notified so the exception is visible and doesn’t quietly become “how we always do it.”
- Escalate to a standing proposal. If the same exception request recurs — multiple teams asking for the same variant, or the same campaign need repeating quarter after quarter — that’s a signal it should become a real proposal for a new token or component, not a permanent exception. Track repeated exception requests as input to the system’s roadmap.
The key principle: an exception process should make the sanctioned path easier than silently forking, and it should route recurring exceptions back into the system rather than letting them pile up as permanent debt. Teams and community health around this process are covered further in Adoption, Community & Support; the underlying component and token architecture these decisions apply to is covered in Building a Design System.
Best Practices
- Write the decision-rights table down and publish it alongside CONTRIBUTING.md — most governance friction comes from ambiguity about who approves what, not from disagreement about the actual rules.
- Match the governance model to actual team maturity, not aspiration. A five-person org running an “open contribution” RFC process is over-engineered; a fifty-team org still requiring every component idea to go through one designer is under-scaled. Revisit the model as the organization grows.
- Make the fast path faster than the workaround. If requesting a new token takes three weeks, contributors will hardcode a value instead. The single biggest lever for keeping a system consistent is making the “right” way also the path of least resistance.
- Automate what should never be a human debate. Formatting, linting, accessibility smoke tests, and changelog generation should run in CI, not in reviewer heads.
- Require evidence in the PR, not just a description. Screenshots, an accessibility checklist, and an explicit breaking-change flag catch problems before merge far more reliably than a reviewer’s memory.
- Make exceptions visible and time-boxed. A silent local override is indistinguishable from fragmentation until it’s discovered months later; a documented, expiring exception with a linked ticket is manageable and gives the core team a feedback loop.
- Review the governance model itself periodically. Treat it like any other part of the system — if the core team is chronically the bottleneck, or if quality is visibly degrading from too much open contribution, that’s a signal to move the model, not just to work harder within it.