Bumble Yury Feb 21, 2024

Refining Compose API for Design Systems

Article Summary

Yury from Bumble Tech tackles a problem every Android team faces: how do you build design system components that are both easy to use and flexible enough for edge cases?

Building custom Compose components for design systems requires balancing strict guidelines with real-world flexibility. This article walks through evolving a NavigationBar component from restrictive to extensible, using techniques borrowed from Material Design 3's own implementation patterns.

Key Takeaways

Critical Insight

The relaxed with Defaults approach delivers extensible components that enforce design system rules without requiring constant API updates for new use cases.

The article reveals how a simple object annotation can make your Composable functions skippable and improve performance.

About This Article

Problem

Design system components in Jetpack Compose involve a difficult choice. Restrictive APIs stop developers from making mistakes, but they need constant updates whenever new use cases come up. Relaxed APIs let developers do more, but they can pollute the global scope and create styling inconsistencies.

Solution

Yury's team used a Defaults object pattern with scoped lambdas. They converted NavigationBarDefaults into a receiver type for composable lambdas. This lets developers access styling functions through the `this` scope instead of typing out explicit prefixes.

Impact

The scoping approach cut down on repeated parameters. ButtonSize only needs to be set once in the Button component instead of being repeated for each Text call. Separate NavigationBarContentScope and NavigationBarButtonScope classes also prevent developers from accidentally using IconButton in the wrong content slots.