# Skeleton & Empty (React Native)

> Loading placeholders that pulse or shimmer, and empty states.

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

> **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/skeleton). The example's source:

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

export function SkeletonDemo() {
  const { tokens } = useKitTheme();
  return (
    <>
      <Section title="Skeleton · pulse">
        <View style={{ flexDirection: "row", gap: 12, alignItems: "center" }}>
          <Skeleton variant="circle" width={48} />
          <View style={{ flex: 1 }}>
            <Skeleton lines={2} lastLineWidth={45} />
          </View>
        </View>
        <Skeleton variant="rect" height={120} label="Loading the chart" />
      </Section>

      <Section title="Skeleton · wave">
        <Skeleton lines={4} animation="wave" />
        <View style={{ flexDirection: "row", gap: 12 }}>
          <Skeleton variant="rect" width="48%" height={90} radius={16} animation="wave" />
          <Skeleton variant="rect" width="48%" height={90} radius={16} animation="wave" />
        </View>
      </Section>

      <Section title="Skeleton · none">
        <Skeleton lines={3} animation="none" />
      </Section>

      <Section title="Empty">
        <View style={{ borderWidth: 1, borderColor: tokens.border, borderRadius: tokens.radius }}>
          <Empty
            icon={<Text style={{ fontSize: 36 }}>🗂️</Text>}
            title="No invoices yet"
            description="Invoices you create or import show up here. Start with one, or import last year's from a spreadsheet."
            actions={
              <>
                <Button>New invoice</Button>
                <Button variant="outline">Import</Button>
              </>
            }
          />
        </View>
        <View style={{ borderWidth: 1, borderColor: tokens.border, borderRadius: tokens.radius }}>
          <Empty size="sm" title="No results" description="Try a shorter search." />
        </View>
      </Section>
    </>
  );
}
```

## Install

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

## Usage

```tsx
import { Skeleton, Empty } from "@/component-lib/skeleton";

<Skeleton variant="text" lines={3} />
<Empty title="No invoices yet" description="Create one to get paid." />
```

## Props

### SkeletonProps

| Prop | Type | Description |
|---|---|---|
| `variant` | `SkeletonVariant` | Default `text`. |
| `lines` | `number` | Number of bars, for `text`. Default 1. |
| `lastLineWidth` | `number` | Width of the last line as a percentage, for `text`. Default 60. |
| `width` | `DimensionValue` | A number is dp; a string is a percentage such as `"50%"`. |
| `height` | `DimensionValue` | A number is dp. Left out, each variant uses its own height, which is what keeps a skeleton the size of the thing it stands in for. |
| `radius` | `number` | Corner radius for `rect`, in dp. |
| `animation` | `SkeletonAnimation` | Default `pulse`. The device's reduce-motion setting turns any of them off. |
| `label` | `string` | Announced while the placeholder is up. Leave it out inside a region that already says it is busy: two announcements are worse than one. |
| `style` | `StyleProp<ViewStyle>` |   |
| `styles` | `Partial<{ root: StyleProp<ViewStyle>; line: StyleProp<ViewStyle> }>` |   |

### EmptyProps

| Prop | Type | Description |
|---|---|---|
| `title` (required) | `ReactNode` | What is missing, in a few words. |
| `description` | `ReactNode` | Why it is empty, and what to do about it. |
| `icon` | `ReactNode` | Decorative: an illustration or icon above the title. |
| `actions` | `ReactNode` | The way out: usually one button, occasionally two. |
| `size` | `"sm" \| "md" \| "lg"` | Default `md`. `sm` suits an empty panel inside a screen. |
| `style` | `StyleProp<ViewStyle>` |   |
| `styles` | `Partial<{ root: StyleProp<ViewStyle>; icon: StyleProp<ViewStyle>; title: StyleProp<Text…` |   |

## Native and web

- Respects the device's Reduce Motion setting.
- Web version: [Skeleton & Empty on the web](https://kit.gramproindia.com/skeleton).
