---
modificationDate: May 19, 2026
title: LoadingIndicator
description: Jetpack Compose loading indicator components for displaying loading state.
sourceCodeUrl: 'https://github.com/expo/expo/tree/main/packages/expo-ui'
packageName: '@expo/ui'
platforms: ['android', 'expo-go']
---

<AgentInstructions>

## Submitting Feedback

If this page contains errors, outdated information, or gaps that blocked you from completing a task, report it so the docs can be improved:

curl -X POST https://api.expo.dev/v2/feedback/docs-send -H 'Content-Type: application/json' -d '{"url":"/versions/unversioned/sdk/ui/jetpack-compose/loadingindicator/","feedback":"🤖 Agent feedback: <specific, actionable description>"}'

Only submit when you have something specific and actionable to report.

</AgentInstructions>

> This is documentation for the next SDK version. For up-to-date documentation, see the [latest version](/versions/latest/sdk/ui/jetpack-compose/loadingindicator) (SDK 56).

# LoadingIndicator

Jetpack Compose loading indicator components for displaying loading state.
Android, Included in Expo Go

> For the complete documentation index, see [llms.txt](/llms.txt). Use this file to discover all available pages.

Expo UI Loading Indicators match the official Jetpack Compose [Loading Indicator API](https://m3.material.io/components/loading-indicator/overview).

## Installation

```sh
npx expo install @expo/ui
```

If you are installing this in an [existing React Native app](/bare/overview), make sure to [install `expo`](/bare/installing-expo-modules) in your project.

## Usage

### Loading indicator

A morphing-shape loading animation from Material 3 Expressive.

```tsx
import { Host, LoadingIndicator } from '@expo/ui/jetpack-compose';

export default function LoadingIndicatorExample() {
  return (
    <Host matchContents>
      <LoadingIndicator />
    </Host>
  );
}
```

### Contained loading indicator

A loading indicator inside a colored background.

```tsx
import { Host, ContainedLoadingIndicator } from '@expo/ui/jetpack-compose';

export default function ContainedLoadingIndicatorExample() {
  return (
    <Host matchContents>
      <ContainedLoadingIndicator />
    </Host>
  );
}
```

### Indeterminate

Omit the `progress` prop to animate continuously without indicating a specific completion level.

```tsx
import { ContainedLoadingIndicator, Host, LoadingIndicator, Row } from '@expo/ui/jetpack-compose';

export default function IndeterminateExample() {
  return (
    <Host matchContents>
      <Row horizontalArrangement={{ spacedBy: 16 }}>
        <LoadingIndicator />
        <ContainedLoadingIndicator />
      </Row>
    </Host>
  );
}
```

### Determinate

Pass an observable state from `useNativeState` as `progress`. Update `progress.value` between `0` and `1`.

```tsx
import {
  ContainedLoadingIndicator,
  Host,
  LoadingIndicator,
  Row,
  useNativeState,
} from '@expo/ui/jetpack-compose';
import { useEffect } from 'react';

export default function DeterminateExample() {
  const progress = useNativeState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      progress.value = (progress.value + 0.05) % 1;
    }, 500);
    return () => clearInterval(interval);
  }, [progress]);

  return (
    <Host matchContents>
      <Row horizontalArrangement={{ spacedBy: 16 }}>
        <LoadingIndicator progress={progress} />
        <ContainedLoadingIndicator progress={progress} />
      </Row>
    </Host>
  );
}
```

## API

```tsx
import { LoadingIndicator, ContainedLoadingIndicator } from '@expo/ui/jetpack-compose';
```

## Components

### `ContainedLoadingIndicator`

Supported platforms: Android.

Type: React.[Element](https://www.typescriptlang.org/docs/handbook/jsx.html#function-component)<ComponentType<[ContainedLoadingIndicatorProps](#containedloadingindicatorprops)\>\>

A loading indicator that displays loading using morphing shapes inside a container.

Matches the Jetpack Compose `ContainedLoadingIndicator`.

ContainedLoadingIndicatorProps

### `containerColor`

Supported platforms: Android.

Optional • Type: [ColorValue](https://reactnative.dev/docs/colors)

Loading indicator's container color

#### Inherited Props

-   [LoadingIndicatorCommonConfig](#loadingindicatorcommonconfig)

### `LoadingIndicator`

Supported platforms: Android.

Type: React.[Element](https://www.typescriptlang.org/docs/handbook/jsx.html#function-component)<ComponentType<[LoadingIndicatorCommonConfig](#loadingindicatorcommonconfig)\>\>

A loading indicator that displays loading using morphing shapes.

Matches the Jetpack Compose `LoadingIndicator`.

## Types

### `LoadingIndicatorCommonConfig`

Supported platforms: Android.

Common props shared by loading indicator variants.

| Property | Type | Description |
| --- | --- | --- |
| color(optional) | [ColorValue](https://reactnative.dev/docs/colors) | Loading indicator color. |
| modifiers(optional) | `ModifierConfig[]` | Modifiers for the component. |
| progress(optional) | [ObservableState](#observablestate)<number | null\> | An observable state that holds the current progress value. Create one with `useNativeState(0)`. Omit for indeterminate loading. |

### `ObservableState`

Supported platforms: Android.

Observable state shared between JavaScript and native views (Jetpack Compose on Android and SwiftUI on iOS).

Type: [SharedObject](/versions/unversioned/sdk/expo#sharedobjecttype) extended by:

| Property | Type | Description |
| --- | --- | --- |
| onChange | `[listener] | null` | A single listener invoked on the native UI runtime whenever the value changes (after iOS `didSet` and Android's setter). Assigning replaces the previous listener; assign `null` to clear. The initial value does not fire `onChange`. The callback must be a worklet so it can run synchronously on the UI thread. Attach it inside `useEffect` and clear it in the cleanup so the listener lifecycle matches the component lifecycle. . Example
```tsx
const state = useNativeState(0);

useEffect(() => {
  state.onChange = (value) => {
    'worklet';
    console.log('changed to', value);
  };
  return () => {
    state.onChange = null;
  };
}, []);
```

 |
| value | `T` | The current value. Writes from a UI worklet are synchronous and immediately readable. Writes from the JS thread are scheduled to the UI thread asynchronously, the new value is not readable until the update has been applied. Prefer writing from a worklet when you need synchronous updates |
