PreviewLab
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
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() } }
)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")
)
)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()
}
}
)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()
}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() }
)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
Functions
Main entry point for PreviewLab that enables interactive preview development with dynamic controls.
Convenience overload for single screen size preview.