100 Days of Compose

One hundred days working through the official Jetpack Compose documentation in order, one topic a day. It starts from what you already know, and ends with the eight ideas the whole toolkit keeps circling. Each post takes a symptom, explains the mechanism underneath it, and shows how to prove it on a real device.

Complete 100 of 100 posts February 19, 2024 – December 6, 2026

Contents — page 2 of 4

Day 26FlowRow is the chip group you kept writing a custom Layout forFlowRow and FlowColumn wrap children onto new lines when they run out of room. They replace the custom Layout most codebases wrote for chip groups, and the overflow API handles the 'and 4 more' case.6 minDay 27Sometimes the right grid is a Column of RowsNot every grid needs LazyVerticalGrid. For a small fixed set — a keypad, a colour picker, a dashboard — a Column of Rows is simpler, cheaper and easier to reason about. Knowing the cutoff matters.6 minDay 28Porting FlexboxLayout: every flex property maps onto something, but not onto one thingThere is no FlexboxLayout in Compose because flex's properties split cleanly across Row/Column, Arrangement, Alignment and FlowRow. A direct property-by-property mapping for anyone porting a View layout.5 minDay 29Screen size is the wrong thing to branch on. Window size is the right one.Window size classes replace device-type checks with a measure of the window your app actually occupies. Three buckets per axis, recomputed live, and the reason isTablet() has been wrong for years.6 minDay 30There are three adaptive layouts, and you probably don't need a fourthMaterial's canonical layouts give three tested patterns for adapting across window sizes. Knowing which one a screen is saves designing an adaptive layout from scratch, and the library implements two of them directly.6 minDay 31ListDetailPaneScaffold: the back button is the whole reason it existsListDetailPaneScaffold adapts a list and detail across window sizes, but its real value is the navigator — which makes back pop the detail on compact and exit the screen on expanded, from one implementation.5 minDay 32SupportingPaneScaffold is for content that is about other contentSupportingPaneScaffold docks secondary content beside a primary view on wide windows and collapses it to a sheet on narrow ones. Choosing it over list-detail is a question about what the second pane contains.6 minDay 33A hinge is a physical object, and your layout should know where it isFoldables give two things a resize doesn't: a posture and a hinge with real coordinates. Handling them well means avoiding the seam and using tabletop mode, not just supporting a new width.6 minDay 34An external display is a second window, not a bigger oneAndroid 16 makes external displays a mainstream concern. The layout work is mostly window size classes you already have; the new parts are density, input capability and deciding what belongs on which screen.6 minDay 35The Scaffold parameter everyone ignores is the one that breaks the layoutScaffold arranges the app shell and hands back the insets its own bars consume. Ignoring that PaddingValues is the single most common Compose layout bug, and edge-to-edge makes it worse.6 minDay 36Five buttons, one hierarchy, and the rule that decides whichMaterial 3 ships five button styles plus the FAB. They form an emphasis hierarchy, and the selection rule is about how many actions compete on a screen rather than about how each one looks.5 minDay 37Checkbox, radio, switch: three controls, three different questionsCheckboxes, radio buttons and switches encode different semantics — multiple choice, exclusive choice, and immediate effect. Choosing by appearance produces interfaces that mislead, and the accessibility story differs too.6 minDay 38The TextField overload you're using is probably the deprecated oneCompose has two TextField APIs. The String + onValueChange pair has real problems with cursor position and asynchronous updates; the TextFieldState overload solves them and is now the recommended one.6 minDay 39A dialog is state, not a function you callDialogs and bottom sheets are composables that exist conditionally, not imperative calls. Modelling them as state fixes the rotation bug, the double-show bug, and the question of where the result goes.6 minDay 40Bar, rail, drawer — the same destinations, chosen by window widthNavigationBar, NavigationRail and the drawer are three presentations of the same destination list. Window size decides which, and NavigationSuiteScaffold does the switching — with rules about how many destinations belong there at all.6 minDay 41The spinner you show for 200ms is worse than no spinnerCompose gives you progress indicators; it doesn't tell you when to show one. Duration decides: under 300ms show nothing, over a second show progress, and never let an indicator replace content that could be a skeleton.6 minDay 42Date pickers are a timezone bug with a calendar attachedCompose's date and time pickers are straightforward components hiding a genuine trap: the selected value is UTC-midnight epoch millis, and converting it naively shifts dates by one in most of the world.6 minDay 43SearchBar has two states, and the second one takes over the screenMaterial 3's SearchBar transitions into a full-screen suggestion surface, which makes it a navigation concern. Chips come in four semantic variants, and the assist/filter/input/suggestion split matters.6 minDay 44MaterialTheme is three CompositionLocals and nothing elseMaterialTheme provides three CompositionLocals and a handful of defaults. Understanding its actual shape explains how components pick up styling, why hardcoded values break dark mode, and what a custom theme has to replace.6 minDay 45Dynamic colour takes your brand palette away, and that's the dealDynamic colour derives a full Material scheme from the user's wallpaper. It improves the feel of most apps and destroys brand recognition if applied indiscriminately, so the interesting work is deciding what stays fixed.6 minDay 46Fifteen named text styles are fewer decisions than fiveMaterial's type scale gives fifteen named roles instead of a font-size parameter. Naming the role rather than the size is what makes typography consistent across a team and correct at large font scales.6 minDay 47Corner radius is a signal, and Material has five of themMaterial's shape scale gives five corner sizes mapped to component categories. The system is simple; the interesting parts are clip ordering, asymmetric corners, and shapes that must respond to state.6 minDay 48Extending MaterialTheme beats replacing it, until it doesn'tMaterial models colour, type and shape. Everything else a design system needs — spacing, motion, semantic colour — has to be added. Extending with a parallel CompositionLocal is usually right; a full custom system rarely is.6 minDay 49Compose is growing a styles API, and it's for the gap theming never coveredMaterialTheme scopes values to a subtree, which is the wrong shape for reusable per-component configuration. Compose's styles direction addresses that gap; wrapper composables are the pattern to use today.5 minDay 50AnnotatedString is why you don't need three Text composables in a RowText takes a String or an AnnotatedString. The second lets one composable carry multiple styles, inline content and clickable spans — replacing the Row of Texts that breaks at large font scales.6 min