
Enhances interactive previews by collecting `@Preview` annotations and creating a playground for UI components, allowing value manipulation, event visualization, and layout exploration.
English | 日本語 | Sample | Documentation | DeepWiki
[!IMPORTANT] This project is still a work in progress, and its API is unstable and may change without any notice. Using this plugin for a hobby project is fine, but we do not recommend using it for production projects yet.
Compose Preview Lab turns @Preview into an interactive Component Playground. You can pass parameters to components, enabling more than just static snapshots—making manual testing easier and helping new developers understand components faster. Compose Multiplatform is supported.
[!NOTE] Compose Preview Lab uses a Kotlin Compiler Plugin to collect
@Previewfunctions. KSP is no longer required.
[!IMPORTANT] Requires Kotlin 2.1.20 or later. See
scripts/supported-kotlin-versions.txtfor the exact list of versions verified by CI.
The easiest way to get started. The starter module bundles all core modules (core, field, ui, preview-lab, gallery) into a
single dependency.
[!NOTE] On Kotlin 2.3.0 or later, plugin application order does not matter — the Gradle plugin injects
-Xcompiler-plugin-orderautomatically. On Kotlin 2.1.20 / 2.2.x, theme.tbsten.compose.preview.labplugin must be applied before the Compose Compiler plugin (the Gradle plugin will fail fast with a clear error otherwise).
plugins {
// ⭐️ Add Compose Preview Lab Gradle plugin
// Kotlin 2.3+: order does not matter (the Gradle plugin auto-injects -Xcompiler-plugin-order)
// Kotlin 2.1.20 / 2.2.x: apply BEFORE composeCompiler
id("me.tbsten.compose.preview.lab") version "<compose-preview-lab-version>"
id("org.jetbrains.kotlin.plugin.compose")
}
kotlin {
sourceSets {
commonMain.dependencies {
// ⭐️ Add Compose Preview Lab starter (includes all core modules)
implementation("me.tbsten.compose.preview.lab:starter:<compose-preview-lab-version>")
}
}
}Then declare a collection point in commonMain. The Compiler Plugin will inject every @Preview it finds into this property.
// src/commonMain/kotlin/Previews.kt
package app
import me.tbsten.compose.preview.lab.collectModulePreviews
val appPreviews by collectModulePreviews()If you need fine-grained control over dependencies, you can add individual modules instead of the starter.
plugins {
// ⭐️ Add Compose Preview Lab Gradle plugin
// Kotlin 2.3+: order does not matter (the Gradle plugin auto-injects -Xcompiler-plugin-order)
// Kotlin 2.1.20 / 2.2.x: apply BEFORE composeCompiler
id("me.tbsten.compose.preview.lab") version "<compose-preview-lab-version>"
id("org.jetbrains.kotlin.plugin.compose")
}
kotlin {
sourceSets {
commonMain.dependencies {
// ⭐️ Add individual modules as needed
implementation("me.tbsten.compose.preview.lab:core:<compose-preview-lab-version>")
implementation("me.tbsten.compose.preview.lab:field:<compose-preview-lab-version>")
implementation("me.tbsten.compose.preview.lab:ui:<compose-preview-lab-version>")
implementation("me.tbsten.compose.preview.lab:preview-lab:<compose-preview-lab-version>")
implementation("me.tbsten.compose.preview.lab:gallery:<compose-preview-lab-version>")
}
}
}Available modules:
| Module | Description |
|---|---|
core |
Core types and interfaces (CollectedPreview, PreviewLabPreview, etc.) |
field |
Field API for interactive parameter editing (StringField, IntField, etc.) |
ui |
Common UI components used by PreviewLab |
preview-lab |
PreviewLab Composable with Field and Event integration |
gallery |
PreviewLabGallery for displaying preview lists |
🚨 WARNING
Pure Android projects (projects that do not use the Kotlin Multiplatform) can also use the Compose Preview Lab, but their functionality is severely limited, such as not being able to browse on the web, and it may be difficult to see the benefits of the Compose Preview Lab. However, the Consider using Compose Multiplatform even if your project is Android-only. I believe that this concept is not limited to Compose Preview Lab, but should be the norm for all projects using Compose in the future.
plugins {
// ⭐️ Add Compose Preview Lab Gradle plugin
// Kotlin 2.3+: order does not matter (the Gradle plugin auto-injects -Xcompiler-plugin-order)
// Kotlin 2.1.20 / 2.2.x: apply BEFORE composeCompiler
id("me.tbsten.compose.preview.lab") version "<compose-preview-lab-version>"
id("org.jetbrains.kotlin.plugin.compose")
}
dependencies {
// ⭐️ Use starter for simple setup (or individual modules if needed)
implementation("me.tbsten.compose.preview.lab:starter:<compose-preview-lab-version>")
}Use PreviewLab Composable and functions such as ***Field() onEvent() to enhance Preview's
Interactive mode.
You can collect @Preview
and create an interactive Playground
like Figma's Component Playground.
@Preview
@Composable
private fun MyButtonPreview() = PreviewLab {
MyButton(
text = fieldValue { StringField("Click Me") },
onClick = { onEvent("MyButton.onClick") },
)
}| Field | Event |
|---|---|
fieldValue { ***Field(defaultValue) } Allows you to manually change values in the Preview. This allows you to say goodbye to the problem of PreviewParameterProvider displaying a large number of Previews and increasing the cognitive load. |
When an event occurs in Preview (common examples: Button#onClick, HomeScreen#onIntent), call onEvent() to visualize the occurrence of the event. |
| TODO image | TODO image |
A solution similar to Compose Preview Lab is Storytale from Jetbrains. The table below shows the differences between the two.
(The following information is current as of 28.6.2025)
| Compose Preview Lab | Storytale | |
|---|---|---|
| Cataloging UI Component | ✅ | ✅ |
| View source code | ❌ Future support is under consideration. |
✅ |
| Ease of preparing the Composable catalog | ✅ Just enclose @Preview in PreviewLab { }. |
You must have the code in the ***Stories source set. Existing code with @Preview must be migrated. |
| Parameter of your own type | ✅ By implementing a custom Field, you can freely customize the UI, including the operation UI. (see). It also provides useful utilities such as SelectableField. |
❌ Not supported. Following the source code shows that there is a non-zero chance of support in the future. |
English | 日本語 | Sample | Documentation | DeepWiki
[!IMPORTANT] This project is still a work in progress, and its API is unstable and may change without any notice. Using this plugin for a hobby project is fine, but we do not recommend using it for production projects yet.
Compose Preview Lab turns @Preview into an interactive Component Playground. You can pass parameters to components, enabling more than just static snapshots—making manual testing easier and helping new developers understand components faster. Compose Multiplatform is supported.
[!NOTE] Compose Preview Lab uses a Kotlin Compiler Plugin to collect
@Previewfunctions. KSP is no longer required.
[!IMPORTANT] Requires Kotlin 2.1.20 or later. See
scripts/supported-kotlin-versions.txtfor the exact list of versions verified by CI.
The easiest way to get started. The starter module bundles all core modules (core, field, ui, preview-lab, gallery) into a
single dependency.
[!NOTE] On Kotlin 2.3.0 or later, plugin application order does not matter — the Gradle plugin injects
-Xcompiler-plugin-orderautomatically. On Kotlin 2.1.20 / 2.2.x, theme.tbsten.compose.preview.labplugin must be applied before the Compose Compiler plugin (the Gradle plugin will fail fast with a clear error otherwise).
plugins {
// ⭐️ Add Compose Preview Lab Gradle plugin
// Kotlin 2.3+: order does not matter (the Gradle plugin auto-injects -Xcompiler-plugin-order)
// Kotlin 2.1.20 / 2.2.x: apply BEFORE composeCompiler
id("me.tbsten.compose.preview.lab") version "<compose-preview-lab-version>"
id("org.jetbrains.kotlin.plugin.compose")
}
kotlin {
sourceSets {
commonMain.dependencies {
// ⭐️ Add Compose Preview Lab starter (includes all core modules)
implementation("me.tbsten.compose.preview.lab:starter:<compose-preview-lab-version>")
}
}
}Then declare a collection point in commonMain. The Compiler Plugin will inject every @Preview it finds into this property.
// src/commonMain/kotlin/Previews.kt
package app
import me.tbsten.compose.preview.lab.collectModulePreviews
val appPreviews by collectModulePreviews()If you need fine-grained control over dependencies, you can add individual modules instead of the starter.
plugins {
// ⭐️ Add Compose Preview Lab Gradle plugin
// Kotlin 2.3+: order does not matter (the Gradle plugin auto-injects -Xcompiler-plugin-order)
// Kotlin 2.1.20 / 2.2.x: apply BEFORE composeCompiler
id("me.tbsten.compose.preview.lab") version "<compose-preview-lab-version>"
id("org.jetbrains.kotlin.plugin.compose")
}
kotlin {
sourceSets {
commonMain.dependencies {
// ⭐️ Add individual modules as needed
implementation("me.tbsten.compose.preview.lab:core:<compose-preview-lab-version>")
implementation("me.tbsten.compose.preview.lab:field:<compose-preview-lab-version>")
implementation("me.tbsten.compose.preview.lab:ui:<compose-preview-lab-version>")
implementation("me.tbsten.compose.preview.lab:preview-lab:<compose-preview-lab-version>")
implementation("me.tbsten.compose.preview.lab:gallery:<compose-preview-lab-version>")
}
}
}Available modules:
| Module | Description |
|---|---|
core |
Core types and interfaces (CollectedPreview, PreviewLabPreview, etc.) |
field |
Field API for interactive parameter editing (StringField, IntField, etc.) |
ui |
Common UI components used by PreviewLab |
preview-lab |
PreviewLab Composable with Field and Event integration |
gallery |
PreviewLabGallery for displaying preview lists |
🚨 WARNING
Pure Android projects (projects that do not use the Kotlin Multiplatform) can also use the Compose Preview Lab, but their functionality is severely limited, such as not being able to browse on the web, and it may be difficult to see the benefits of the Compose Preview Lab. However, the Consider using Compose Multiplatform even if your project is Android-only. I believe that this concept is not limited to Compose Preview Lab, but should be the norm for all projects using Compose in the future.
plugins {
// ⭐️ Add Compose Preview Lab Gradle plugin
// Kotlin 2.3+: order does not matter (the Gradle plugin auto-injects -Xcompiler-plugin-order)
// Kotlin 2.1.20 / 2.2.x: apply BEFORE composeCompiler
id("me.tbsten.compose.preview.lab") version "<compose-preview-lab-version>"
id("org.jetbrains.kotlin.plugin.compose")
}
dependencies {
// ⭐️ Use starter for simple setup (or individual modules if needed)
implementation("me.tbsten.compose.preview.lab:starter:<compose-preview-lab-version>")
}Use PreviewLab Composable and functions such as ***Field() onEvent() to enhance Preview's
Interactive mode.
You can collect @Preview
and create an interactive Playground
like Figma's Component Playground.
@Preview
@Composable
private fun MyButtonPreview() = PreviewLab {
MyButton(
text = fieldValue { StringField("Click Me") },
onClick = { onEvent("MyButton.onClick") },
)
}| Field | Event |
|---|---|
fieldValue { ***Field(defaultValue) } Allows you to manually change values in the Preview. This allows you to say goodbye to the problem of PreviewParameterProvider displaying a large number of Previews and increasing the cognitive load. |
When an event occurs in Preview (common examples: Button#onClick, HomeScreen#onIntent), call onEvent() to visualize the occurrence of the event. |
| TODO image | TODO image |
A solution similar to Compose Preview Lab is Storytale from Jetbrains. The table below shows the differences between the two.
(The following information is current as of 28.6.2025)
| Compose Preview Lab | Storytale | |
|---|---|---|
| Cataloging UI Component | ✅ | ✅ |
| View source code | ❌ Future support is under consideration. |
✅ |
| Ease of preparing the Composable catalog | ✅ Just enclose @Preview in PreviewLab { }. |
You must have the code in the ***Stories source set. Existing code with @Preview must be migrated. |
| Parameter of your own type | ✅ By implementing a custom Field, you can freely customize the UI, including the operation UI. (see). It also provides useful utilities such as SelectableField. |
❌ Not supported. Following the source code shows that there is a non-zero chance of support in the future. |