
Compose Multiplatform Patterns
Ship shared Compose UI across Android, iOS, Desktop, and Web with consistent state, navigation, theming, and recomposition-aware performance.
Overview
Compose Multiplatform Patterns is an agent skill for the Build phase that teaches shared Jetpack Compose and Compose Multiplatform UI patterns for state, navigation, theming, and performance.
Install
npx skills add https://github.com/affaan-m/everything-claude-code --skill compose-multiplatform-patternsWhat is this skill?
- ViewModel + single StateFlow screen state collected in Compose
- Shared navigation and theming patterns across Android, iOS, Desktop, and Web
- Reusable composables and design-system guidance
- Recomposition and rendering performance practices
- Activates for Jetpack Compose and Compose Multiplatform KMP projects
- Covers state management, navigation, theming, and performance as four pattern areas
- Targets Android, iOS, Desktop, and Web from shared Compose code
Adoption & trust: 4.4k installs on skills.sh; 210k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your KMP app UI drifts per platform because state, navigation, and theming lack a single Compose-first pattern library.
Who is it for?
Builders actively shipping Compose Multiplatform or Jetpack Compose features who want copy-paste-ready architectural patterns.
Skip if: Greenfield projects still choosing React Native or Flutter—or teams with no Kotlin Multiplatform in scope.
When should I use this skill?
Building Compose UI (Jetpack Compose or Compose Multiplatform), managing UI state with ViewModels, implementing navigation in KMP or Android, designing reusable composables, or optimizing recomposition.
What do I get? / Deliverables
You implement screens with a consistent ViewModel–StateFlow–Compose loop, shared navigation and theme structure, and performance habits that reduce unnecessary recomposition.
- Screen state models and ViewModel wiring patterns
- Navigation and theme structure aligned to KMP targets
- Performance-minded composable implementations
Recommended Skills
Journey fit
Compose Multiplatform patterns apply while you are building client UI in a KMP product, before ship-time polish and distribution. The skill is entirely about composables, ViewModel state collection, navigation graphs, and design-system structure—canonical frontend mobile/desktop UI work.
How it compares
Pattern library for Compose UI architecture, not a scaffolding generator or CI ship checklist.
Common Questions / FAQ
Who is compose-multiplatform-patterns for?
Solo and indie developers using Kotlin Multiplatform with Compose who need opinionated patterns for state, navigation, and theming across mobile and desktop targets.
When should I use compose-multiplatform-patterns?
In the Build frontend subphase when implementing Compose UI, managing ViewModel state, adding KMP navigation, designing reusable composables, or optimizing recomposition before ship.
Is compose-multiplatform-patterns safe to install?
It is documentation and code-pattern guidance without bundled executables; review the Security Audits panel on this Prism page and treat snippets as templates to adapt in your repo.
Workflow Chain
Then invoke: kotlin patterns
SKILL.md
READMESKILL.md - Compose Multiplatform Patterns
# Compose Multiplatform Patterns Patterns for building shared UI across Android, iOS, Desktop, and Web using Compose Multiplatform and Jetpack Compose. Covers state management, navigation, theming, and performance. ## When to Activate - Building Compose UI (Jetpack Compose or Compose Multiplatform) - Managing UI state with ViewModels and Compose state - Implementing navigation in KMP or Android projects - Designing reusable composables and design systems - Optimizing recomposition and rendering performance ## State Management ### ViewModel + Single State Object Use a single data class for screen state. Expose it as `StateFlow` and collect in Compose: ```kotlin data class ItemListState( val items: List<Item> = emptyList(), val isLoading: Boolean = false, val error: String? = null, val searchQuery: String = "" ) class ItemListViewModel( private val getItems: GetItemsUseCase ) : ViewModel() { private val _state = MutableStateFlow(ItemListState()) val state: StateFlow<ItemListState> = _state.asStateFlow() fun onSearch(query: String) { _state.update { it.copy(searchQuery = query) } loadItems(query) } private fun loadItems(query: String) { viewModelScope.launch { _state.update { it.copy(isLoading = true) } getItems(query).fold( onSuccess = { items -> _state.update { it.copy(items = items, isLoading = false) } }, onFailure = { e -> _state.update { it.copy(error = e.message, isLoading = false) } } ) } } } ``` ### Collecting State in Compose ```kotlin @Composable fun ItemListScreen(viewModel: ItemListViewModel = koinViewModel()) { val state by viewModel.state.collectAsStateWithLifecycle() ItemListContent( state = state, onSearch = viewModel::onSearch ) } @Composable private fun ItemListContent( state: ItemListState, onSearch: (String) -> Unit ) { // Stateless composable — easy to preview and test } ``` ### Event Sink Pattern For complex screens, use a sealed interface for events instead of multiple callback lambdas: ```kotlin sealed interface ItemListEvent { data class Search(val query: String) : ItemListEvent data class Delete(val itemId: String) : ItemListEvent data object Refresh : ItemListEvent } // In ViewModel fun onEvent(event: ItemListEvent) { when (event) { is ItemListEvent.Search -> onSearch(event.query) is ItemListEvent.Delete -> deleteItem(event.itemId) is ItemListEvent.Refresh -> loadItems(_state.value.searchQuery) } } // In Composable — single lambda instead of many ItemListContent( state = state, onEvent = viewModel::onEvent ) ``` ## Navigation ### Type-Safe Navigation (Compose Navigation 2.8+) Define routes as `@Serializable` objects: ```kotlin @Serializable data object HomeRoute @Serializable data class DetailRoute(val id: String) @Serializable data object SettingsRoute @Composable fun AppNavHost(navController: NavHostController = rememberNavController()) { NavHost(navController, startDestination = HomeRoute) { composable<HomeRoute> { HomeScreen(onNavigateToDetail = { id -> navController.navigate(DetailRoute(id)) }) } composable<DetailRoute> { backStackEntry -> val route = backStackEntry.toRoute<DetailRoute>() DetailScreen(id = route.id) } composable<SettingsRoute> { SettingsScreen() } } } ``` ### Dialog and Bottom Sheet Navigation Use `dialog()` and overlay patterns instead of imperative show/hide: ```kotlin NavHost(navController, startDestination = HomeRoute) { composable<HomeRoute> { /* ... */ } dialog<ConfirmDeleteRoute> { backStackEntry -> val