Skip to main content

Reference a component in a story

By default, a story just calls a component directly, like any other composable. But when you want a safe reference to it — used by @CStory(component = ...) to power the catalog's documentation panel — CStories provides @CStoryComponent.

Annotate your component

// lib/src/commonMain/kotlin/.../PrimaryButton.kt
import io.cstories.annotations.CStoryComponent

/**
* High-emphasis filled button, used for the main call-to-action.
*
* @param text Label displayed inside the button.
* @param onClick Called when the button is clicked.
*/
@CStoryComponent
@Composable
fun PrimaryButton(text: String, onClick: () -> Unit) { /* ... */ }

@CStoryComponent can be applied to a top-level function or an object/companion object member function.

Applying the components plugin

This requires applying an additional, lightweight plugin directly on the module that declares the component (:lib, not :lib:stories): id("io.cstories.gradle.components"). Unlike id("io.cstories.gradle") (the catalog plugin), this one doesn't apply Compose Multiplatform, doesn't require a jvm()/wasmJs() target, and doesn't wire any catalog/entry-point task — it only wires KSP to process @CStoryComponent and generate io.cstories.generated.CStoryComponentRefs, an object exposing one FQN constant per annotated function:

// lib/build.gradle.kts
plugins {
kotlin("multiplatform") version "2.2.0"
id("io.cstories.gradle.components") version "0.1.0-SNAPSHOT"
}

This is required whenever the component and the story that demonstrates it live in different Gradle modules (the :lib / :lib:stories split — see Structure a multi-module project): KSP only ever scans annotated symbols within the module it's currently processing, never across a dependency boundary. Applying io.cstories.gradle.components directly on :lib generates CStoryComponentRefs locally, in the same compilation where the component's KDoc is still visible as source.

Referencing the component from a story

import io.cstories.annotations.CStory
import io.cstories.generated.CStoryComponentRefs

@CStory(collection = "DesignSystem", group = "Button", name = "Primary", component = CStoryComponentRefs.PrimaryButton)
@Composable
fun PrimaryButtonStory() {
PrimaryButton(text = "Click me", onClick = {})
}

When this isn't needed

If your component and its story live in the same module (a single-module setup, applying only io.cstories.gradle), @CStoryComponent and id("io.cstories.gradle.components") aren't required at all — component = "..." can be omitted, or @CStoryComponent can still be used purely for the safe-reference benefit, without the extra plugin (the catalog plugin already wires the same KSP processing for components declared in its own module).

What's next

Once a component is annotated, its KDoc can also power the catalog's documentation panel — see Document a component.