Spinner

An animated loading indicator that stands in for an icon.

import { Spinner } from "@delacour/native-ui/spinner";
Sizes
Sizes
import { SPINNER_SIZES, Spinner } from "@delacour/native-ui/spinner";import { Text } from "@delacour/native-ui/text";import type { ReactElement } from "react";import { View } from "react-native";export function Demo(): ReactElement {	return (		<View className="flex-row flex-wrap items-center gap-6">			{SPINNER_SIZES.map((size) => (				<View className="items-center gap-2" key={size}>					<Spinner size={size} />					<Text.Caption size="xs">{size}</Text.Caption>				</View>			))}			<View className="items-center gap-2">				<Spinner size={40} />				<Text.Caption size="xs">40pt</Text.Caption>			</View>		</View>	);}
<Spinner />
<Spinner size="lg" color="danger" speed={0.7} />

Sizes: the icon scale, shared outright — SPINNER_SIZES is ICON_SIZES, xs through 2xl (14/16/18/20/24/32pt) — or an explicit number. A spinner stands in for an icon, so the two must agree on what md means.

Colours: default, success, warning, danger, plus any token the theme emits (primary-foreground, muted-foreground) or a literal (#EC4899).

A Tailwind palette name like emerald-500 only resolves if some utility class already pulled that variable into the build — otherwise the token is unresolved and nothing is drawn. Prefer the semantic tokens.

Size and colour are inherited

Colours
Colours
import { SPINNER_COLORS, Spinner } from "@delacour/native-ui/spinner";import { Text } from "@delacour/native-ui/text";import type { ReactElement } from "react";import { View } from "react-native";export function Demo(): ReactElement {	return (		<View className="flex-row flex-wrap items-center gap-6">			{SPINNER_COLORS.map((color) => (				<View className="items-center gap-2" key={color}>					<Spinner color={color} size="lg" />					<Text.Caption size="xs">{color}</Text.Caption>				</View>			))}			<View className="items-center gap-2">				<Spinner color="info" size="lg" />				<Text.Caption size="xs">info</Text.Caption>			</View>			<View className="items-center gap-2">				<Spinner color="#EC4899" size="lg" />				<Text.Caption size="xs">#EC4899</Text.Caption>			</View>		</View>	);}

Through exactly one path: the nearest IconDefaultsProvider, falling back to md on foreground. A Button already wraps the spinner it composes in with its own icon class and variant foreground, so the spinner does not read the button's context — a second path would recompute the same two values and could drift from them.

An explicit size or color always wins.

Custom glyphs

Any child is the glyph, wrapped in a Spinner.Content automatically so it still rotates. Write Spinner.Content out by hand only when the rotating layer itself needs styling.

speed belongs to the root and rides the spinner's context, so every part turns at one rate: 1 is one full turn per 900ms.

Layout

The root is the only sized box. Spinner.Content is size-full and the arc carries no width or height at all — react-native-svg resolves both to '100%' when neither is set.

That size-full is load-bearing. Content-size the middle layer and the percentage resolves against an indefinite parent, collapsing the glyph to zero.

The arc

The default glyph is drawn from SVG primitives, not a Central Icon — the set has no loader glyph. Rule 5 governs icons; primitives are fine.

Its caps are butt, and its round head is a separate Circle. The two half-rings share the endpoint at the bottom of the ring; round caps there stack, and two semi-transparent discs composite to roughly 0.8 alpha — a bright dot straddling the joint, opposite the head, at every size. Do not put strokeLinecap="round" back.

The gradient stops are angle-compensated and run in user space. A linear gradient fades along its axis, but a point at angle θ clockwise from the top sits at y = 12 - 10·cos θ — so two stops alone make the fade stall near 3 and 9 o'clock and race through 12 and 6.

ReduceMotion.Never is deliberate

Under the default System policy withTiming completes instantly while the OS reduce-motion setting is on, so withRepeat(-1) would spin a zero-length animation forever. A status indicator is not decorative motion.

API

Prop

Type

Spinner.Content

The rotating layer itself. Written out by hand only when that layer needs styling — any child of Spinner is wrapped in one automatically.

Prop

Type

size and color are inherited through exactly one path — the nearest IconDefaultsProvider — falling back to md on foreground. A Button already wraps the spinner it composes in with its own icon class and variant foreground, so the spinner does not read the button's context: a second path would recompute the same two values and could drift from them.

On this page