ComponentContextFactory in Decompose: How It Creates Isolated Child Component Contexts

ComponentContextFactory is a functional interface in the Decompose library that constructs isolated component contexts for child components by combining Lifecycle, StateKeeper, InstanceKeeper, and BackHandler services.

When building navigation flows in Decompose (arkivanov/decompose), parent components must spawn child components with their own isolated lifecycles and state management. The ComponentContextFactory centralizes this creation logic, ensuring every child receives properly configured Essenty services without tight coupling to specific context implementations.

What Is ComponentContextFactory?

Located in decompose/src/commonMain/kotlin/com/arkivanov/decompose/ComponentContextFactory.kt, ComponentContextFactory is a functional interface that knows how to build a new component context from the four Essenty services required by every Decompose component.

Parameter Purpose
Lifecycle Controls the start/stop lifecycle of the component.
StateKeeper Persists state across process recreation.
InstanceKeeper Holds singleton‑like objects for the component’s whole lifetime.
BackHandler Handles back‑button events (Android) or other “back” actions.
fun interface ComponentContextFactory<out T : Any> {
    operator fun invoke(
        lifecycle: Lifecycle,
        stateKeeper: StateKeeper,
        instanceKeeper: InstanceKeeper,
        backHandler: BackHandler,
    ): T
}

Why ComponentContextFactory Is Required for Child Components

When a navigation model (e.g., a Router, a StackNavigator, or a ChildSlotNavigator) creates a child component, it must provide that child with an isolated context containing its own lifecycle, state‑keeping, instance‑keeping, and back‑handling. The factory encapsulates the creation logic so the navigation model does not need to know the concrete type of the context (plain ComponentContext, JetpackComponentContext, or any custom implementation).

  • Decoupling: The navigation infrastructure works with the abstract ComponentContextFactory<T> rather than a concrete context class.
  • Customization: Apps can supply their own factory (e.g., to create a JetpackComponentContext that also exposes a SavedStateHandle).
  • Testability: Tests can inject a simple factory returning DefaultComponentContext to verify navigation behavior.

How ComponentContextFactory Works in Practice

Default Factory Usage in Parent Components

The default implementation of ComponentContext provides its own factory via ComponentContextFactoryOwner. In DefaultComponentContext.kt, the factory is exposed so parent components can create isolated child contexts.

class RootComponent(
    componentContext: ComponentContext
) : ComponentContextOwner by componentContext {

    // Router that will create child components
    private val router = router<Config, Child>(initialStack = listOf(Config.First))

    // The factory comes from the parent context (DefaultComponentContext)
    private val childFactory = componentContext.componentContextFactory

    private fun createChild(config: Config): Child {
        // Build a fresh child context using the factory
        val childContext = childFactory(
            lifecycle = LifecycleRegistry(),
            stateKeeper = StateKeeper(),
            instanceKeeper = InstanceKeeper(),
            backHandler = BackHandler()
        )
        return Child(childContext, config)
    }
}

Custom Factory for Jetpack Integration

For Android Jetpack integration, DefaultJetpackComponentContext.kt supplies a factory that creates JetpackComponentContext objects. This allows child components to access Jetpack‑specific APIs like SavedStateHandle while maintaining the same creation pattern.

class JetpackRootComponent(
    componentContext: JetpackComponentContext
) : ComponentContextOwner by componentContext {

    // Use the Jetpack‑specific factory
    private val childFactory: ComponentContextFactory<JetpackComponentContext> =
        componentContext.componentContextFactory

    private fun createJetpackChild(): JetpackChild {
        val childContext = childFactory(
            lifecycle = componentContext.lifecycle,
            stateKeeper = componentContext.stateKeeper,
            instanceKeeper = componentContext.instanceKeeper,
            backHandler = componentContext.backHandler
        )
        return JetpackChild(childContext)
    }
}

Testing with Factory Injection

In unit tests, you can inject a simple factory that returns DefaultComponentContext instances. This is demonstrated in the test utilities where ComponentContextFactory enables verification of router behavior without requiring full Android infrastructure.

class RouterTest {

    // Simple factory that creates a DefaultComponentContext
    private val testFactory = ComponentContextFactory(::DefaultComponentContext)

    @Test
    fun `router creates child with proper context`() {
        val router = TestRouter(
            factory = testFactory,
            childFactory = { ctx, config -> TestChild(ctx, config) }
        )
        // ...assertions about lifecycle, stateKeeper etc.
    }
}

Key Implementation Files

File Role
[ComponentContextFactory.kt](https://github.com/arkivanov/decompose/blob/master/decompose/src/commonMain/kotlin/com/arkivanov/decompose/ComponentContextFactory.kt) Defines the functional interface that creates component contexts.
[ComponentContextFactoryOwner.kt](https://github.com/arkivanov/decompose/blob/master/decompose/src/commonMain/kotlin/com/arkivanov/decompose/ComponentContextFactoryOwner.kt) Interface for objects that expose a ComponentContextFactory.
[DefaultComponentContext.kt](https://github.com/arkivanov/decompose/blob/master/decompose/src/commonMain/kotlin/com/arkivanov/decompose/DefaultComponentContext.kt) Standard implementation of a component context and its factory.
[DefaultChildItemFactory.kt](https://github.com/arkivanov/decompose/blob/master/decompose/src/commonMain/kotlin/com/arkivanov/decompose/router/children/DefaultChildItemFactory.kt) Uses a ComponentContextFactory to create child contexts for navigation models.
[DefaultJetpackComponentContext.kt](https://github.com/arkivanov/decompose/blob/master/jetpack-component-context/src/commonMain/kotlin/com/arkivanov/decompose/jetpackcomponentcontext/DefaultJetpackComponentContext.kt) Example of a custom context type with its own factory.
[TestComponentContext.kt](https://github.com/arkivanov/decompose/blob/master/decompose-test-utils/src/commonMain/kotlin/com/arkivanov/decompose/testutils/TestComponentContext.kt) Shows how the factory is used in test utilities.

Summary

  • ComponentContextFactory is a functional interface in ComponentContextFactory.kt that constructs component contexts from four Essenty services: Lifecycle, StateKeeper, InstanceKeeper, and BackHandler.
  • It enables decoupled child creation by allowing navigation models to instantiate child components without knowing the concrete context type.
  • The factory pattern supports customization for platform-specific implementations like JetpackComponentContext and improves testability through dependency injection.
  • Routers use ComponentContextFactory via DefaultChildItemFactory.kt to ensure each child receives an isolated context with properly wired lifecycle and state management.

Frequently Asked Questions

What parameters does ComponentContextFactory require?

ComponentContextFactory accepts four parameters: a Lifecycle for controlling component start/stop states, a StateKeeper for persisting state across process recreation, an InstanceKeeper for holding singleton-like objects during the component's lifetime, and a BackHandler for managing back-button events. These parameters are defined in the invoke operator function in ComponentContextFactory.kt.

How does ComponentContextFactory differ from ComponentContext itself?

While ComponentContext is the interface that components implement to access lifecycle and state services, ComponentContextFactory is the functional interface responsible for creating those context instances. Think of ComponentContext as the container of services, and ComponentContextFactory as the builder that assembles new containers for each child component.

Can I create a custom ComponentContextFactory for my own context type?

Yes, you can implement a custom ComponentContextFactory to create specialized context types like JetpackComponentContext. By implementing the functional interface and providing your own logic in the invoke operator, you can expose additional platform-specific APIs (such as Android's SavedStateHandle) while maintaining compatibility with Decompose's navigation infrastructure.

Where is ComponentContextFactory used in the Decompose router?

The router uses ComponentContextFactory through DefaultChildItemFactory.kt to instantiate fresh contexts for each child in a navigation stack. When the router pushes a new configuration, it invokes the factory to create a child-specific Lifecycle, StateKeeper, InstanceKeeper, and BackHandler, ensuring proper isolation and lifecycle propagation between parent and child components.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →