Percent strategy (compose.percent / code.percent)

April 11, 2026 · View on GitHub

What it is

Percent provides two API families:

  1. psdp / phdp / pwdp (and Sp variants) — scales the base value linearly with the chosen axis, equivalent to multiplying by dim/300 when applyAspectRatio is off; with a, uses the same correction family as scaled (difference from base and aspect).
  2. space* extensions (DimenPercentSpace.kt) — interpret the receiver as 0–100 and return (percent/100)×axisOrReference(\text{percent} / 100) \times \text{axisOrReference} in dp (or px for *Px variants), using the current Configuration axis or the given reference length.

Calculation used

  • psdp / phdp / pwdp: in calculatePercentDpCompose, without AR: base×dim×(1/300)\text{base} \times \text{dim} \times (1/300). With AR: aligned with adjustment from difference vs 300 dp and logNormalizedAr (as scaled with AR).
  • space*: always computes a length in dp (or px for *Px), including in multi-window when the library’s heuristic marks the window as constrained: the axis read is still the current window’s screenWidthDp / screenHeightDp / smallestScreenWidthDp (or the reference length). Variants with i pass ignoreMultiWindows = true into the pipeline (affects psdp-style scaling elsewhere; space* still returns a fractional length, not a raw 50 for “50%”).

Suffixes a, i, ia and inverters follow the global library pattern.

Mirrored Compose surface: every sdp / hdp / wdp / ssp… name becomes psdp / phdp / pwdp / pssp… with the same suffix rules (a, i, ia, Px, Ph, …). See the prefix column in COMPOSE-API-CONVENTIONS.md §3 and facilitators p*Rotate, p*Mode, p*Qualifier, p*Screen in compose.percent and code.percent (DimenPercentDpExtensions.kt, DimenPercentSpExtensions.kt).

How to use

import com.appdimens.dynamic.compose.percent.psdp
import com.appdimens.dynamic.compose.percent.spaceW

Modifier.padding(12.psdp)
Modifier.width(10.spaceW) // 10% of Configuration.screenWidthDp

Code: com.appdimens.dynamic.code.percent — mirrors extensions and DimenPercentDp / DimenPercentSp for px and dp.

Use space* when you need a literal screen percentage; use psdp when you want the same design “token” as other strategies but with a 1/300-style law on the axis (and optional AR).


Literal space* API (compose.percentDimenPercentSpace.kt)

Contract: the receiver is the percentage 0–100 (e.g. 10 → 10% of the chosen axis or reference). i / Wi / Swi / … variants set ignoreMultiWindows = true for APIs that forward that flag; space* results remain dp (or px) derived from the same percentage formula, not the literal receiver value.

Screen-axis Dp / px (no extra args)

MemberReturnsMeaningExample
spaceWDp% of screenWidthDpModifier.width(15.spaceW)
spaceWiDpsame + ignore multi-windowModifier.width(15.spaceWi)
spaceWPxFloatpxval x = 15.spaceWPx
spaceWPxiFloatpx + ival x = 15.spaceWPxi
spaceSwDp% of smallestScreenWidthDpModifier.height(20.spaceSw)
spaceSwiDp+ iModifier.height(20.spaceSwi)
spaceSwPxFloatpx20.spaceSwPx
spaceSwPxiFloatpx + i20.spaceSwPxi
spaceHDp% of screenHeightDpModifier.height(12.spaceH)
spaceHiDp+ iModifier.height(12.spaceHi)
spaceHPxFloatpx12.spaceHPx
spaceHPxiFloatpx + i12.spaceHPxi

Reference length % (Dp or Number as dp)

MemberReturnsMeaningExample
space(reference: Dp)Dp% of reference.value25.space(200.dp)
space(reference: Number)Dp% of reference dp25.space(200)
spacePx(reference: Dp)Floatpx25.spacePx(200.dp)
spacePx(reference: Number)Floatpx25.spacePx(200)
spaceI(reference: Dp)Dp+ ignore multi-window25.spaceI(180.dp)
spaceI(reference: Number)Dp+ i25.spaceI(180)
spacePxi(reference: Dp)Floatpx + i25.spacePxi(180.dp)
spacePxi(reference: Number)Floatpx + i25.spacePxi(180)

TextUnit (sp) — same geometry as dp result; fontScale optional

MemberReturnsExample
spaceWSp(fontScale = true, ignoreMultiWindows = false)TextUnitText("A", fontSize = 5.spaceWSp())
spaceWSpi(fontScale = true)TextUnitText("A", fontSize = 5.spaceWSpi())
spaceWSpPx(...)Floatval px = 5.spaceWSpPx()
spaceWSpiPx()Float5.spaceWSpiPx()
spaceSwSp / spaceSwSpi / spaceSwSpPx / spaceSwSpiPxsame pattern for swText("B", fontSize = 4.spaceSwSp())
spaceHSp / spaceHSpi / spaceHSpPx / spaceHSpiPxsame for heightText("C", fontSize = 3.spaceHSp())
spaceSp(reference: Dp, …)TextUnitText("D", fontSize = 10.spaceSp(200.dp))
spaceSp(reference: Number, …)TextUnit10.spaceSp(200)
spaceSpi(reference: Dp) / spaceSpi(reference: Number)TextUnit + i10.spaceSpi(200.dp)
spaceSpPx / spaceSpiPxFloat10.spaceSpPx(200.dp)

Recommendation: prefer spaceW / spaceSw / spaceH for true layout %-columns; keep psdp for token-style scaling. For psdp / pssp and other scaled-style APIs, test i in split-screen (may return unscaled base when the multi-window heuristic applies); space* keeps the % of axis semantics.

Why use it

For layouts where size should track one screen edge uniformly, or for “always X% of width” columns, without the implicit tablet damping of some other curves.

When to use it

  • Full-width columns, proportional gutters, typography tied to a real % of the window (space*).
  • When scaled with AR still does not give the desired proportion across two axes.

Advantages and trade-offs

  • Pros: clear linear math (without AR); space* separates “design dp” from “% of screen”.
  • Cons: without AR, growth on tablets can be stronger than power; combine psdp with i carefully in split-screen (behavior differs from space* percentage lengths).

Define most UI tokens with scaled; reserve percent where the design spec is explicitly percentage-based or linear along an edge. Validate multi-window behavior for psdp / i; space* continues to express a true % of window in dp.

Back to index