Spin
Lightweight loading indicator with size presets, a determinate progress ring, a network variant for AI work, and a children overlay mode.
import { Spin } from '@lobehub/ui/base-ui';Basic
APIs
childrennull | string | number | bigint | false | true | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<AwaitedReactNode>indicatornull | string | number | bigint | false | true | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<AwaitedReactNode>percentnumberrefnull | (instance: HTMLDivElement | null) => void | (() => VoidOrUndefinedOnly) | DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES] | RefObject<HTMLDivElement | null>Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref).
sizenumber | 'large' | 'middle' | 'small'Defaults to
"middle".spinningbooleanDefaults to
true.styleCSSPropertiestipnull | string | number | bigint | false | true | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<AwaitedReactNode>variant'default' | 'network'Defaults to
"default".
Also accepts all native HTML and ARIA attributes.
Spin renders a native <div>. All standard div HTML attributes including className, style, data-*, and ref are forwarded to the root element.
Sizes
size accepts small (14px), middle (20px, default), large (32px), or any raw pixel number.
Determinate progress
Pass percent (0–100) with the default variant to render a progress ring driven by stroke-dashoffset instead of the spinning glyph.
Network variant
variant="network" renders a layered-network glyph: nodes pulse, particles flow between layers, and a dashed ring rotates. Every animated property is transform or opacity, so it runs on the compositor and stays static under prefers-reduced-motion.
Use it only when the user is waiting on a model or agent. Plain network requests use the default variant.
Which indicator to use
| Waiting on | Component | Size |
|---|---|---|
| A button or icon action | Button loading / ActionIcon loading | follows the button |
| Background sync next to a title or list item | Spin | small |
| A model or agent (reasoning, tool call, task step) | Spin variant="network" | small inline, middle inside a card |
| The first token of a chat message | LoadingDots from @lobehub/ui/chat | 12 |
| A panel whose layout is unknown | Spin variant="network" centered | large |
| A panel whose layout is known | Skeleton | — |
| Existing content being replaced | Spin wrapping children | middle |
| The app itself | BrandLoading from @lobehub/ui/brand | 40 |
Do not hand-roll spinners, use Icon spin, antd Spin, or third-party loading packages.
Overlaying content
When children is provided, Spin wraps it in a relative container and overlays a centered spinner (plus optional tip) on top while spinning is true. Set spinning={false} to render only the children.
Migrating from antd Spin
import { Spin } from '@lobehub/ui/base-ui';
<Spin spinning={loading} tip="Loading…">
<Content />
</Spin>;delay and fullscreen are not supported; gate spinning yourself and use Spin inside your own fullscreen container if needed.
antd's size="default" becomes size="middle".