# Spinner (React Native)

> Loading indicators with a delay so fast loads never flash.

GramproKit for React Native · Feedback · Beta · Source: https://kit.gramproindia.com/native/docs/spinner

> **Beta:** React Native support is in beta. APIs may change or break between prereleases (npm tag `native`).

_Interactive demo:_ [open the live example](https://kit.gramproindia.com/native/docs/spinner). The example's source:

```tsx
import { useState } from "react";
import { Text, View } from "react-native";
import { Button } from "@/component-lib/button";
import { useKitTheme } from "@/component-lib/shared/native";
import { Spinner } from "@/component-lib/spinner";
import { Row, Section } from "./layout"; // Section and Row: page layout for the demo

export function SpinnerDemo() {
  const { tokens } = useKitTheme();
  const [busy, setBusy] = useState(false);
  return (
    <>
      <Section title="Spinner · sizes">
        <Row>
          <Spinner size="xs" />
          <Spinner size="sm" />
          <Spinner size="md" />
          <Spinner size="lg" />
          <Spinner size="xl" />
          <Spinner size={56} color={tokens.success} />
        </Row>
      </Section>

      <Section title="Spinner · dots and labels">
        <Row>
          <Spinner variant="dots" size="lg" />
          <Spinner variant="dots" size="xl" color={tokens.danger} />
          <Spinner showLabel label="Fetching invoices…" />
          <Spinner variant="dots" showLabel />
        </Row>
      </Section>

      <Section title="Spinner · covering content (delay 150 ms, min 600 ms)">
        <Spinner loading={busy} delay={150} minDuration={600} style={{ borderRadius: tokens.radius }}>
          <View style={{ padding: 16, borderRadius: tokens.radius, borderWidth: 1, borderColor: tokens.border, gap: 10 }}>
            <Text style={{ color: tokens.fg, fontSize: tokens.fontSize, fontWeight: "600" }}>Monthly report</Text>
            <Text style={{ color: tokens.muted, fontSize: tokens.fontSize }}>
              While loading, this panel takes no touches and is hidden from screen readers.
            </Text>
            <Button variant="outline" size="sm" onPress={() => setBusy(true)}>
              Refresh
            </Button>
          </View>
        </Spinner>
        <Button variant="secondary" onPress={() => setBusy((b) => !b)}>
          {busy ? "Stop loading" : "Start loading"}
        </Button>
      </Section>
    </>
  );
}
```

## Install

```bash
npx @grampro/kit@native add Spinner
```

## Usage

```tsx
import { Spinner } from "@/component-lib/spinner";

<Spinner loading={pending} delay={200} label="Loading invoices" />
```

## Props

### SpinnerProps

| Prop | Type | Description |
|---|---|---|
| `loading` | `boolean` | Default true. With `children`, the spinner covers them while this is true. |
| `size` | `SpinnerSize \| number` | Default `md` (24 dp); a number is dp. |
| `variant` | `SpinnerVariant` | Default `ring`. |
| `color` | `string` | Colour of the indicator. Default: the accent colour (the web uses `currentColor`). |
| `label` | `string` | What screen readers announce. Default "Loading". |
| `showLabel` | `boolean` | Show the label next to the spinner. |
| `delay` | `number` | Milliseconds to wait before showing, so fast work doesn't flash. Default 0. |
| `minDuration` | `number` | Once shown, stay at least this many milliseconds. Default 0. |
| `children` | `ReactNode` | Content to cover while loading. It stops taking touches and is hidden from screen readers. |
| `style` | `StyleProp<ViewStyle>` |   |
| `styles` | `Partial<{ root: StyleProp<ViewStyle>; status: StyleProp<ViewStyle>; indicator: StylePro…` |   |
| `localeText` | `Partial<SpinnerLocaleText>` |   |

Also accepts the props of `Omit<ViewProps, "children" | "style">`.

## Native and web

- Takes a `color` (native has no `currentColor`); defaults to the accent.
- Web version: [Spinner on the web](https://kit.gramproindia.com/spinner).
