The component catalog for Kotlin Compose Multiplatform

Your components deserve more than a folder of previews.

Turn your composables into interactive stories. Explore every state, share a clear catalog, and keep your design system close to the code.

> Kotlin first. Your components, no black magic.

CStories catalog preview with story navigation, live preview, and interactive controls
PrimaryButtonStory.kt @CStory(name = "Primary") fun PrimaryButtonStory() {   PrimaryButton(label = "Click") {} }
BUILT FOR YOUR STACK
K Kotlin Compose Multiplatform ↗ Desktop/Wasm ⌘ Gradle & KSP

LESS FRICTION, MORE FEEDBACK

A better development loop.

A dedicated space to build, try, and document your components.

Stories, not magic

Write regular Compose functions. The @CStory annotation makes them visible in the catalog.

Test every state

Tweak parameters on the fly with interactive controls and see your components come to life.

Desktop or browser

Generate a desktop catalog or share a web version compiled with Kotlin/Wasm.

FROM CODE TO UI

Stay in your environment.

CStories fits into your Kotlin workflow: the Gradle plugin and KSP generate the catalog from your stories. No separate preview app to maintain.

See how it works
@CStory(
    collection = "DesignSystem",
    group = "Buttons",
    name = "Primary",
    component = CStoryComponentRefs.DemoButton,
)
@Composable
fun DemoButtonPrimaryStory() {
    var label by remember { mutableStateOf("Save changes") }
    var isEnabled by remember { mutableStateOf(true) }
    var isLoading by remember { mutableStateOf(false) }

    KnobPanel {
        TextKnob(label = "Text", value = label, onValueChange = { label = it }, codeKey = "label")
        BooleanKnob(label = "Enabled", value = isEnabled, onValueChange = { isEnabled = it }, codeKey = "isEnabled")
        BooleanKnob(label = "Loading", value = isLoading, onValueChange = { isLoading = it }, codeKey = "isLoading")
    }

    DemoButton(
        text = label,
        onClick = {},
        variant = ButtonVariant.Primary,
        enabled = isEnabled,
        loading = isLoading,
    )
}
Your stories stay in Kotlin

YOUR NEXT COMPONENT IS READY

Turn your components
into an experience worth exploring.

Get started with CStories