# KitFlow
KitFlow is a Kotlin Multiplatform SDK for building adaptive Compose UI with small, reusable utilities.
KitFlow is not a Material theme wrapper. It does not replace Text, Button, Column, Row, Card, or Material components. It helps you keep adaptive values and adaptive layout decisions clean.
The responsive design will come from proper code arrangement. KitFlow will help with proper coding.
Add Maven Central:
repositories {
mavenCentral()
}Add the SDK:
dependencies {
implementation("io.github.vedangj72:kit-flow:1.0.3")
}Use the latest version you have published.
Use AdaptiveKitProvider once near the root of your Compose app.
@Composable
fun App() {
AdaptiveKitProvider {
MainScreen()
}
}Everything inside this provider can use KitFlow APIs.
Use Adaptive.value(...) when a value should change by screen class.
val screenPadding = Adaptive.value(
sm = 12.dp,
md = 16.dp,
lg = 20.dp,
tab = 32.dp,
desktop = 48.dp
)
Column(
modifier = Modifier.padding(screenPadding)
) {
Text("Hello KitFlow")
}Adaptive.value(...) is generic, so it works with Dp, TextUnit, Int, Float, Color, shapes, and your own classes.
val titleSize = Adaptive.value(
sm = 18.sp,
md = 20.sp,
lg = 22.sp,
tab = 26.sp,
desktop = 32.sp
)
Text(
text = "Adaptive title",
fontSize = titleSize,
maxLines = 1,
overflow = TextOverflow.Ellipsis
)For text, always think about truncation, wrapping, and large font scale. Adaptive size alone is not enough.
KitFlow supports:
SM
MD
LG
TAB
DESKTOP
Default thresholds:
MD >= 360dp
LG >= 480dp
TAB >= 600dp
DESKTOP >= 840dp
Fallback rules:
SM -> sm
MD -> md
LG -> lg
TAB -> tab ?: lg
DESKTOP -> desktop ?: tab ?: lg
So this is valid:
val spacing = Adaptive.value(
sm = 8.dp,
md = 12.dp,
lg = 16.dp
)If tab or desktop is missing, KitFlow falls back safely to lg.
Each app can decide what SM, MD, LG, TAB, and DESKTOP mean.
AdaptiveKitProvider(
breakpointThresholds = AdaptiveBreakpointThresholds(
md = 400,
lg = 520,
tab = 720,
desktop = 1000
)
) {
App()
}Use custom thresholds when your product design needs different screen classes.
Use Adaptive.onOrientationChange(...) only when portrait and landscape need different UI.
Adaptive.onOrientationChange(
portrait = { info ->
Column {
LeftPanel()
RightPanel()
}
},
landscape = { info ->
Row {
LeftPanel(modifier = Modifier.weight(1f))
RightPanel(modifier = Modifier.weight(1f))
}
}
)Do not use orientation branching for every small value. For padding, text size, color, radius, and spacing, prefer Adaptive.value(...).
Read current window state with rememberWindowInfo().
val info = rememberWindowInfo()
Text("widthDp: ${info.widthDp}")
Text("heightDp: ${info.heightDp}")
Text("screenClass: ${info.screenClass}")
Text("layoutClass: ${info.layoutClass}")
Text("orientation: ${info.orientation}")Important difference:
screenClass = stable screen class based on shortest side
layoutClass = current width-based class
orientation = Portrait / Landscape / Square / Unknown
This prevents a phone from being treated like a tablet only because it rotated.
KitFlow helps keep UI stable when font scale increases.
val accessibility = LocalAdaptiveAccessibilityInfo.currentAvailable values:
accessibility.fontScale
accessibility.fontScaleClass
accessibility.minimumTouchTarget
accessibility.reducedMotion
accessibility.highContrast
accessibility.differentiateWithoutColorUse AdaptiveAccessibleLayout when a Row may break with large text.
AdaptiveAccessibleLayout(
normal = {
Row {
Title()
Actions()
}
},
largeText = {
Column {
Title()
Actions()
}
}
)Use adaptiveTouchTarget() for clickable UI.
Modifier
.adaptiveTouchTarget()
.clickable { onClick() }Use adaptiveSemantics() for clear labels and state.
Modifier.adaptiveSemantics(
label = "Download file",
role = Role.Button
)Use AdaptiveIconButton for icon-only actions.
AdaptiveIconButton(
icon = Icons.Default.Close,
contentDescription = "Close",
onClick = onClose
)Icon-only buttons must have meaningful labels.
There are certain things to keep in mind while making layouts or components in Jetpack Compose:
- Keep the layout system in mind.
- Draw the layout on paper first when the UI has multiple states.
- Consider portrait and landscape mode, along with state changes.
- Avoid fixed size, height, and width unless the element truly requires it.
- Do not hardcode height, width, or size for responsive containers.
- Prefer
aspectRatio(...),weight(...),fillMaxWidth(),widthIn(...),heightIn(...), and constraints. - For text, use
maxLines, wrapping strategy, andTextOverflow.Ellipsiswhere needed. - Use vertical scroll for simple static content that may overflow.
- Use
LazyColumnorLazyRowfor lists. - Review official Compose adaptive layouts and pick the correct layout strategy.
- If KitFlow fits the case, use KitFlow to keep adaptive values consistent.
Example with official window size class style:
when (windowSizeClass) {
WindowWidthSizeClass.Compact -> {
Column {
LeftPanel()
RightPanel()
}
}
WindowWidthSizeClass.Medium,
WindowWidthSizeClass.Expanded -> {
Row {
LeftPanel(
modifier = Modifier.weight(1f)
)
RightPanel(
modifier = Modifier.weight(1f)
)
}
}
}With KitFlow, the same idea can be kept inside your SDK-driven layout flow:
val info = rememberWindowInfo()
when (info.layoutClass) {
AdaptiveBreakpoint.SM,
AdaptiveBreakpoint.MD -> {
Column {
LeftPanel()
RightPanel()
}
}
AdaptiveBreakpoint.LG,
AdaptiveBreakpoint.TAB,
AdaptiveBreakpoint.DESKTOP -> {
Row {
LeftPanel(modifier = Modifier.weight(1f))
RightPanel(modifier = Modifier.weight(1f))
}
}
}KitFlow does not remove the need to understand Compose layout. It helps you arrange adaptive code in one clear flow.
Keep these official docs close while designing adaptive Compose UI:
- Support different display sizes
- Build adaptive apps
- Compose layout basics
- Adaptive do's and don'ts
- Material Design 3 in Compose
KitFlow should resolve adaptive context and adaptive values, not own the UI.
Developers keep using normal Compose components. KitFlow helps those components adapt.