PreviewLab

open class PreviewLab(defaultState: @Composable () -> PreviewLabState = { rememberPreviewLabStateFromUrl() }, defaultScreenSizes: List<ScreenSize> = ScreenSize.SmartphoneAndDesktops, contentRoot: @Composable (content: @Composable () -> Unit) -> Unit = { it() }, defaultIsHeaderShow: @Composable () -> Boolean = { LocalDefaultIsHeaderShow.current }, defaultInspectorTabs: @Composable () -> List<InspectorTab> = { InspectorTab.defaults }, disableTrailingLambda: Nothing? = null)

PreviewLab is a powerful preview environment for Compose UI components that enables interactive development and testing. It provides dynamic field controls, event tracking, and multi-device previews to enhance the development experience.

Basic Usage

Use PreviewLab as a wrapper around your preview composables to enable interactive controls:

@Preview
@Composable
private fun MyButtonPreview() = PreviewLab {
val buttonText by fieldState { StringField("Text", "Click Me!") }
val isEnabled by fieldState { BooleanField("Enabled", true) }
val variant by fieldState { EnumField<ButtonVariant>("Variant", ButtonVariant.Primary) }

MyButton(
text = buttonText,
enabled = isEnabled,
variant = variant,
onClick = { onEvent("Button clicked") }
)
}

Key Features

Interactive Fields

  • fieldState: Creates mutable fields for interactive state management

  • fieldValue: Creates read-only fields for parameter configuration

  • Built-in field types: StringField, BooleanField, IntField, EnumField, SelectableField, etc.

Event Tracking

  • onEvent: Records user interactions and displays toast notifications

  • Events are logged in the Events tab for debugging and testing

Multi-Device Preview

  • screenSizes: Test components across different screen sizes simultaneously

  • Built-in presets for smartphones, tablets, and desktop devices

Visual Controls

  • Inspector Panel: Right sidebar with fields, events, and settings

  • Zoom and Pan: Scale and move preview content for detailed inspection

  • Device Frames: Visual device boundaries for accurate sizing

Advanced Usage

Custom PreviewLab Instance

Create reusable PreviewLab configurations:

val myPreviewLab = PreviewLab(
defaultScreenSizes = ScreenSize.AllPresets,
defaultState = { remember { PreviewLabState() } }
)

@Composable
private fun MyComponentPreview() = myPreviewLab {
MyComponent()
}

Complex Field Combinations

Combine multiple fields for comprehensive testing:

PreviewLab {
val theme by fieldState { EnumField<AppTheme>("Theme", AppTheme.Light) }
val language by fieldState { SelectableField<Locale>("Language") {
choice(Locale.ENGLISH, "English", isDefault = true)
choice(Locale.JAPANESE, "日本語")
}}
val isLoading by fieldState { BooleanField("Loading State", false) }

MyApp(theme = theme, locale = language, isLoading = isLoading)
}

Constructor Parameters

Parameters

defaultState

Factory for creating the default PreviewLabState. Controls state persistence and initialization. By default, uses rememberSaveable for automatic state persistence across recompositions.

Usage examples:

// Default behavior - state persists across recompositions
PreviewLab() // Uses rememberSaveable internally

// Non-persistent state - resets on every recomposition
PreviewLab(
defaultState = { remember { PreviewLabState() } }
)

// Custom retained state (requires Rin library)
PreviewLab(
defaultState = { remember { PreviewLabState() } }
)
defaultScreenSizes

List of screen sizes to display in the preview. Controls which device form factors are available for testing. Defaults to ScreenSize.SmartphoneAndDesktops.

Usage examples:

// Default - smartphone and desktop sizes
PreviewLab() // Uses ScreenSize.SmartphoneAndDesktops

// All available presets including tablets
PreviewLab(
defaultScreenSizes = ScreenSize.AllPresets
)

// Only mobile devices for focused testing
PreviewLab(
defaultScreenSizes = listOf(ScreenSize.Phone, ScreenSize.Tablet)
)

// Custom screen sizes for specific requirements
PreviewLab(
defaultScreenSizes = listOf(
ScreenSize(360.dp, 640.dp, "Small Phone"),
ScreenSize(1920.dp, 1080.dp, "Full HD Desktop")
)
)
contentRoot

Wrapper composable that surrounds the entire PreviewLab UI. Useful for providing custom themes, composition locals, or other global configuration.

Usage examples:

// Default - no wrapper, uses PreviewLabTheme only
PreviewLab() // Uses { it() }

// Apply custom Material3 theme like customizedPreviewLab
PreviewLab(
contentRoot = { content ->
MaterialTheme(
colorScheme = lightColorScheme(
primary = Color.Red,
onPrimary = Color.Yellow
)
) {
content()
}
}
)

// Provide composition locals for your design system
PreviewLab(
contentRoot = { content ->
MyDesignSystem {
CompositionLocalProvider(
LocalCustomTypography provides customTypography,
LocalBranding provides myBranding
) {
content()
}
}
}
)

// Add global error boundary and logging
PreviewLab(
contentRoot = { content ->
ErrorBoundary(onError = { error -> logError(error) }) {
content()
}
}
)
defaultIsHeaderShow

Controls whether the PreviewLab header is visible. When set to false, hides the header controls (scale, inspector panel toggle, etc.) to provide a cleaner preview view. Defaults to true.

Usage examples:

// Default - header is visible
PreviewLab() // Header shown

// Hide header for embedded preview
PreviewLab(
isHeaderShow = false
) {
MyComponent()
}
defaultInspectorTabs

List of tabs to display in the inspector panel. Defaults to InspectorTab.defaults which shows the built-in Fields and Events tabs.

Usage examples:

// Default - Fields and Events tabs only
PreviewLab() // Uses InspectorTab.defaults

// Add custom tabs alongside default tabs
val myPreviewLab = PreviewLab(
defaultInspectorTabs = { InspectorTab.defaults + listOf(DebugTab) }
)

// Only custom tabs (no default Fields/Events)
val customOnlyPreviewLab = PreviewLab(
defaultInspectorTabs = { listOf(CustomTab1, CustomTab2) }
)

// No tabs at all
val noTabsPreviewLab = PreviewLab(
defaultInspectorTabs = { emptyList() }
)
disableTrailingLambda

Technical parameter to prevent the invoke method from being treated as a trailing lambda. Always null and has no functional purpose.

Usage example:

// This parameter is always null - you don't need to specify it
PreviewLab(
defaultScreenSizes = ScreenSize.AllPresets
// disableTrailingLambda is automatically null
) {
// Preview content
}

See also

Main entry point for creating preview content

State management for preview controls and configuration

Scope providing field and event functions

Device screen size configuration for multi-device testing

Inheritors

Constructors

Link copied to clipboard
constructor(defaultState: @Composable () -> PreviewLabState = { rememberPreviewLabStateFromUrl() }, defaultScreenSizes: List<ScreenSize> = ScreenSize.SmartphoneAndDesktops, contentRoot: @Composable (content: @Composable () -> Unit) -> Unit = { it() }, defaultIsHeaderShow: @Composable () -> Boolean = { LocalDefaultIsHeaderShow.current }, defaultInspectorTabs: @Composable () -> List<InspectorTab> = { InspectorTab.defaults }, disableTrailingLambda: Nothing? = null)

Types

Link copied to clipboard

PreviewLab companion object with default settings.

Functions

Link copied to clipboard
open operator fun invoke(modifier: Modifier = Modifier, state: PreviewLabState = defaultState(), screenSizes: List<ScreenSize> = defaultScreenSizes, isHeaderShow: Boolean = this.defaultIsHeaderShow(), inspectorTabs: List<InspectorTab> = this.defaultInspectorTabs(), isInPreviewLabGalleryCardBody: Boolean = LocalIsInPreviewLabGalleryCardBody.current, contentGraphicsLayer: GraphicsLayer = rememberGraphicsLayer(), content: @Composable PreviewLabScope.() -> Unit)

Main entry point for PreviewLab that enables interactive preview development with dynamic controls.

operator fun invoke(maxWidth: Dp, maxHeight: Dp, modifier: Modifier = Modifier, state: PreviewLabState = defaultState(), isHeaderShow: Boolean = this.defaultIsHeaderShow(), inspectorTabs: List<InspectorTab> = this.defaultInspectorTabs(), isInPreviewLabGalleryCardBody: Boolean = LocalIsInPreviewLabGalleryCardBody.current, contentGraphicsLayer: GraphicsLayer = rememberGraphicsLayer(), content: @Composable PreviewLabScope.() -> Unit)

Convenience overload for single screen size preview.