Design systems on Android · Series · Part 1 of 6

What a design system is, and a tour of a working one for Android

Khairul Alam·October 2026·~6 min read
Design systemAndroidKotlinAtomic design

A design system is easy to admire and hard to build, because the finished product hides the decisions. This series builds one for Android in plain Views and Kotlin, with no Jetpack Compose, and points at real, running code for every claim. In this first part you will learn what a design system is made of, why teams build them, and how the working example is laid out so you can find your way around it.

Working code. Everything in this post exists and runs in the reference repository: github.com/liconrepo/MobileDesignSystem. Clone it and follow along; the docs are also published at liconrepo.github.io/MobileDesignSystem.

Files for this part:

Part 1 in 60 seconds
  • A design system is a shared language: tokens (named decisions), components (reusable parts) and guidance (when to use what).
  • It pays off through consistency, speed and accessibility that is fixed once and inherited everywhere.
  • Two ideas organise the example: functional vs perceptual patterns, and atoms to pages.
  • The repo has a library module, a gallery app and a docs folder. You can run it in about five minutes.

What a design system actually is

Ask five people and you will get five answers: a Figma file, a component library, a style guide, a team. They are all pieces of the same thing. A useful working definition for engineers is:

Analogy. Think of a city's building code and its catalogue of approved parts. The code says how wide a door must be (rules). The catalogue offers doors that already comply (components). The measurements everyone agrees on, such as metres and standard sizes, are the tokens. A builder who uses them does not re-argue every decision, and the buildings still feel like one city.

In an app, that becomes three layers of material:

PieceWhat it isExample in the repo
TokensNamed design decisions: colours, spacing, radius, type sizesmds_color_primary, mds_space_lg
ComponentsReusable UI built from tokensMdsButton, MdsTextField
GuidancePrinciples and usage rules, written downdocs/principles.md, docs/components.md

Without the third row you have a library, not a system. Rules like "one primary button per region" are what stop a good set of parts from producing an inconsistent product.

Why teams build one

It is not free. A system has a maintenance cost, a versioning story and a risk of becoming a bottleneck. The practical advice in this series is to keep it small: every component must justify itself, and the public surface stays deliberate.

Two ideas that organise the example

Functional and perceptual patterns

Alla Kholmatova's book Design Systems: A Practical Guide to Creating Design Languages for Digital Products (Smashing Magazine, 2017) separates two kinds of pattern. Functional patterns are about what something does: a button triggers an action, a text field collects text. Perceptual patterns are about how it feels: the corner radius, the type scale, the way a success message looks compared with an error. The book also argues for a shared vocabulary and for written, testable principles. This series paraphrases those ideas in its own words and does not reproduce the book.

In code, the split is practical. Perceptual decisions live in resource files (res/values) and a few helpers. Functional behaviour lives in Kotlin classes. A rebrand touches the first; a bug fix touches the second.

Atoms, molecules, organisms, templates, pages

Brad Frost's Atomic Design describes growing an interface from small parts to whole screens. The example library uses the same names for its packages, so a newcomer can predict where a file lives.

Perceptual: tokens, tone, motion, theme helpers Atoms: MdsButton, MdsBadge, MdsChip, MdsAvatar, MdsSkeleton Molecules: MdsTextField, MdsAlert, MdsListItem Organisms: MdsCard Templates: MdsScreenTemplate · Pages: your app
Each layer is built from the ones below it. Pages are app code, not library code.

A tour of the working repo

Clone it and look around. Every later part of this series points back to files in here.

git clone https://github.com/liconrepo/MobileDesignSystem.git
cd MobileDesignSystem
./gradlew :sample:installDebug      # run the gallery on a device or emulator
./gradlew :designsystem:test        # unit tests

You need JDK 17 and the Android SDK (compileSdk 36, minSdk 24). The layout is:

MobileDesignSystem/
  designsystem/                       the library (what you would publish)
    src/main/java/io/github/liconrepo/mds/
      perceptual/                     MdsTone, MdsMotion, theme helpers
      functional/atoms/               MdsButton, MdsBadge, MdsChip, MdsAvatar, MdsSkeleton
      functional/molecules/           MdsTextField, MdsAlert, MdsListItem
      functional/organisms/           MdsCard
      templates/                      MdsScreenTemplate
    src/main/res/
      values/                         palette, semantic colours, dimens, attrs, themes, type
      values-night/                   the dark-mode values
  sample/                             a gallery app that consumes the library
  docs/                               principles, tokens, theming, layers, component guidelines
The gallery app in the light theme The gallery app in the dark theme The gallery app with the Sunset brand The gallery showing alerts, avatars and list items
The sample app: light, dark, an alternate brand, and a component page. The same components, three looks.

Why a sample app belongs in the repo

A component you cannot see is a component you cannot trust. The gallery has one tab per layer, and the foundations tables (colours, type scale, spacing) are drawn from the live theme, so the documentation cannot drift away from the code. It is also the consumer-side test: if the sample is awkward to write, the API is wrong.

The ground rules this series follows

  1. Roles, not values. Code asks for "primary" or "danger", never for #4040D8.
  2. Never colour alone. Errors have an icon and a prefix, selected chips have a check mark.
  3. 48dp touch targets, even when the control looks smaller.
  4. Small public API. Kotlin's explicitApi() is switched on, so nothing is public by accident.
  5. Everything original. Colours, icons and code were written for this project from public documentation. It is not affiliated with any company, and the credits in the README name the public systems whose ideas informed it: Material Design, IBM Carbon, Shopify Polaris, GitHub Primer, Atlassian and Microsoft Fluent.

What comes next

PartYou will learn
2Tokens in three tiers, dark mode, and swapping brands
3Building a themeable component, using the button
4State and accessibility in the text field, chip and alert
5Layers, and a screen template with named regions
6Publishing, CI, docs, and the bugs I hit along the way

Try it yourself

  1. Run the sample and flip dark mode and the Sunset brand. Notice what changes and what does not.
  2. Open designsystem/src/main/res/values/mds_colors.xml and its twin in values-night. Find the same name in both files.
  3. Open MdsButton.kt and search for a hex colour. There is not one.
TermIn plain words
Design systemTokens, components and guidance that a product team shares.
TokenA named design decision, such as a colour or a spacing step.
ComponentA reusable UI part built from tokens.
Functional patternWhat a part does.
Perceptual patternHow a part looks and feels.
Atom / molecule / organismSmall standalone part / atoms working as one unit / a whole section of a screen.
Template / pageA screen layout with no content / that layout filled with real content.
← Back to all writing