Previews

A view written as an extension on VIEViewScope needs a scope and a model to render, and no ViewModel. EmptyVIE is the scope to use in a preview.

Previewing a view

EmptyVIE<Intent, Signal> is a VIEViewScope with nothing behind it: post discards the intent, and signalFlow never emits, so SignalEffect never fires. It holds no model, so the model goes straight to the view:

Counter.kt
@Preview
@Composable
fun CounterPreview() {
    EmptyVIE<Intent, Signal>().Counter(
        model = Model(count = 3, saving = true), (1)
    )
}
1 Any state of the screen can be previewed, here a save in progress.

EmptyVIE is part of vie-mvi, so previews can live next to the views, in the main source set.

Preview dependencies

@Preview comes from Compose’s tooling, which VIE does not bring. With the Compose Multiplatform Gradle plugin applied:

build.gradle.kts
kotlin {
    sourceSets {
        commonMain.dependencies {
            implementation("org.jetbrains.compose.ui:ui-tooling-preview:1.12.0") (1)
        }
        jvmMain.dependencies {
            runtimeOnly("org.jetbrains.compose.ui:ui-tooling:1.12.0") (2)
        }
    }
}
1 The @Preview annotation.
2 What the IDE uses to render the preview, here for the desktop target; add it to androidMain too for an Android target. It is only for the IDE, yet it ships with whatever depends on that source set: in an Android app module, use debugImplementation.
To check what a view posts, or how it reacts to a signal, use MockVIE instead.