Individual skill
avoiding-subcomposition-pitfalls
Use this skill when a Compose tree uses SubcomposeLayout, BoxWithConstraints, or Scaffold and the developer reports extra measure passes, slow first frame, or layout passes running content composition repeatedly. Covers why SubcomposeLayout composes its slots during the measure phase, why BoxWithConstraints forces a subcomposition for every new Constraints value, why nesting Scaffold or BoxWithConstraints multiplies the cost, when a custom Layout or Modifier.layout { } replaces SubcomposeLayout, and how to use SubcomposeLayoutState's slot reuse policy and precompose APIs when SubcomposeLayout is genuinely required. Use when the developer mentions BoxWithConstraints, SubcomposeLayout, Scaffold, "extra measure pass", "double measurement", "first frame slow", "subcompose", or notices that wrapping content in BoxWithConstraints regresses scroll perf inside a LazyColumn.
recomposition/avoiding-subcomposition-pitfalls/SKILL.md
Source commit 1b32f81724c0d71fe9ef093ca44697f559fdab6e
What was checked
- Matches the observed repository HEAD
- Yes
- Scanner rules are current
- No
- Repository scan complete
- No
- Skill scan complete
- No
- Observed behavior
- Not checked yet
- Last checked
- Nov 6, 2026
These are observations at the recorded commit, not a guarantee of safety. Review the source before running it.
Install this skill
Choose an agent in your Stack or copy a command below. Commands fetch the pinned commit and copy only this skill directory. Existing destinations are refused. Copying a command does not install anything.
An install command is unavailable: current rules, complete repository and skill scans, an eligible behavior level and a permitted license are required.
Repository context
- Repository stars (not skill ratings)
- 526
- Repository last updated
- Jun 16, 2026
- License
- Apache-2.0
Observed agent integration: No specific integration evidence. Standard SKILL.md installation does not imply verified compatibility.
- agent-skills Repository topic
- android Repository topic
- claude Repository topic
- claude-code Repository topic
- compose Repository topic
- jetpack-compose Repository topic
- kotlin Repository topic
- llm-tools Repository topic
- recomposition Repository topic
- skydoves Repository topic
- engineering Derived category
- writing Derived category
Declared tags are partial or unavailable.
Files and excerpt
File metadata and permitted, redacted excerpts come from the recorded scan. Source links are pinned to that commit.
Browse files
Read excerpt
# Avoiding Subcomposition Pitfalls — Keep Composition Out of the Measure Pass
`SubcomposeLayout` runs its content's composition **during the measure pass**, not during the parent's composition pass. That trades extra layout cost for the ability to use measured constraints inside the children's composition. `BoxWithConstraints`, `material3.Scaffold`, and the lazy layouts are all built on top of it, so the cost is invisible until it nests or lands inside a hot path. This skill teaches Claude how to detect the misuse, how to replace `SubcomposeLayout` with a cheaper primitive when its power is not needed, and how to keep it efficient when it is.
## When to use this skill
- The developer wraps content in `BoxWithConstraints` purely to read `maxWidth` / `maxHeight` and pick between a few composables, and the screen feels heavy at first frame or on configuration change (rotation, IME show).
- A `BoxWithConstraints` or `Scaffold` is nested inside another `BoxWithConstraints` or `Scaffold`, multiplying subcomposition cost.
- A `BoxWithConstraints` sits inside a `LazyColumn`/`LazyRow` item and the developer reports scroll jank that did not exist before the wrap was added.
- The developer manually authors a `SubcomposeLayout` block but only uses constraints to compute final positions, never to drive child composition.
- The Layout Inspector or a Perfetto trace shows `Compose:applyChanges` or measure-phase composition counts that scale with parent constraint changes (rotation, drag-to-resize, animated container size).
- A custom `SubcomposeLayout`'s `measurePolicy` block allocates a fresh composable lambda inside `subcompose(slotId) { … }` on every measurement. AndroidX maintains an internal lint check named `ComposableLambdaInMeasurePolicy` (in `compose/lint/internal-lint-checks/`) that flags exactly this pattern on its own codebase; published APIs like `BoxWithConstraints`, `material.Scaffold`, and `material3.TabRow` suppress that check because the trade-off is fundamental to their public contract. App-side code that reproduces the pattern pays the same cost without the suppression rationale.
## When NOT to use this skill