Command Palette

Search for a command...

Spinner

An indicator that can be used to show a loading state.

Processing payment...
$100.00
import { styled } from "styled-system/jsx";
import { Item, ItemContent, ItemMedia, ItemTitle } from "@/components/ui/item";
import { Spinner } from "@/components/ui/spinner";

export default function SpinnerDemo() {
  return (
    <styled.div
      css={{ display: "flex", w: "full", maxW: "xs", flexDir: "column", gap: "4", rounded: "1rem" }}
    >
      <Item variant="muted">
        <ItemMedia>
          <Spinner />
        </ItemMedia>
        <ItemContent>
          <ItemTitle css={{ lineClamp: "1" }}>Processing payment...</ItemTitle>
        </ItemContent>
        <ItemContent css={{ flex: "none", justifyContent: "flex-end" }}>
          <styled.span css={{ textStyle: "sm", fontVariantNumeric: "tabular-nums" }}>
            $100.00
          </styled.span>
        </ItemContent>
      </Item>
    </styled.div>
  );
}

Installation

npx nore-ui-cli@latest add spinner

Usage

import { Spinner } from "@/components/ui/spinner";
<Spinner />

Customization

You can replace the default spinner icon with any other icon by editing the Spinner component.

import { LuLoader } from "react-icons/lu";
import { styled } from "styled-system/jsx";
import { spinner } from "styled-system/recipes";

const Spinner = styled(LuLoader, spinner, {
  defaultProps: {
    role: "status",
    "aria-label": "Loading",
  },
});

export default function SpinnerCustom() {
  return (
    <styled.div css={{ display: "flex", alignItems: "center", gap: "4" }}>
      <Spinner />
    </styled.div>
  );
}
import { LuLoader } from "react-icons/lu";
import { styled } from "styled-system/jsx";
import { spinner } from "styled-system/recipes";

const Spinner = styled(LuLoader, spinner, {
  defaultProps: {
    role: "status",
    "aria-label": "Loading",
  },
});

export { Spinner };

Examples

Size

Use width and height to change the size of the spinner.

import { styled } from "styled-system/jsx";
import { Spinner } from "@/components/ui/spinner";

export default function SpinnerSize() {
  return (
    <styled.div css={{ display: "flex", alignItems: "center", gap: "6" }}>
      <Spinner css={{ w: "3", h: "3" }} />
      <Spinner css={{ w: "4", h: "4" }} />
      <Spinner css={{ w: "6", h: "6" }} />
      <Spinner css={{ w: "8", h: "8" }} />
    </styled.div>
  );
}

Color

Use color to change the color of the spinner.

import { styled } from "styled-system/jsx";
import { Spinner } from "@/components/ui/spinner";

export default function SpinnerColor() {
  return (
    <styled.div css={{ display: "flex", alignItems: "center", gap: "6" }}>
      <Spinner css={{ w: "6", h: "6", color: "red.500" }} />
      <Spinner css={{ w: "6", h: "6", color: "green.500" }} />
      <Spinner css={{ w: "6", h: "6", color: "blue.500" }} />
      <Spinner css={{ w: "6", h: "6", color: "yellow.500" }} />
      <Spinner css={{ w: "6", h: "6", color: "purple.500" }} />
    </styled.div>
  );
}

Button

Add a spinner to a button to indicate a loading state. The <Button /> will handle the spacing between the spinner and the text.

import { styled } from "styled-system/jsx";
import { Button } from "@/components/ui/button";
import { Spinner } from "@/components/ui/spinner";

export default function SpinnerButton() {
  return (
    <styled.div css={{ display: "flex", flexDir: "column", alignItems: "center", gap: "4" }}>
      <Button disabled size="sm">
        <Spinner />
        Loading...
      </Button>
      <Button variant="outline" disabled size="sm">
        <Spinner />
        Please wait
      </Button>
      <Button variant="secondary" disabled size="sm">
        <Spinner />
        Processing
      </Button>
    </styled.div>
  );
}

Badge

You can also use a spinner inside a badge.

SyncingUpdatingProcessing
import { styled } from "styled-system/jsx";
import { Badge } from "@/components/ui/badge";
import { Spinner } from "@/components/ui/spinner";

export default function SpinnerBadge() {
  return (
    <styled.div
      css={{
        display: "flex",
        alignItems: "center",
        gap: "4",
        "& > .badge": {
          rounded: "1.2rem",
        },
      }}
    >
      <Badge>
        <Spinner />
        Syncing
      </Badge>
      <Badge variant="secondary">
        <Spinner />
        Updating
      </Badge>
      <Badge variant="outline">
        <Spinner />
        Processing
      </Badge>
    </styled.div>
  );
}

Input Group

Input Group can have spinners inside <InputGroupAddon>.

Validating...
import { LuArrowUp } from "react-icons/lu";
import { styled } from "styled-system/jsx";
import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupInput,
  InputGroupTextarea,
} from "@/components/ui/input-group";
import { Spinner } from "@/components/ui/spinner";

export default function SpinnerInputGroup() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "md", flexDir: "column", gap: "4" }}>
      <InputGroup>
        <InputGroupInput placeholder="Send a message..." disabled />
        <InputGroupAddon align="inline-end">
          <Spinner />
        </InputGroupAddon>
      </InputGroup>
      <InputGroup>
        <InputGroupTextarea placeholder="Send a message..." disabled />
        <InputGroupAddon align="block-end">
          <Spinner /> Validating...
          <InputGroupButton css={{ ml: "auto" }} variant="primary">
            <LuArrowUp />
            <styled.span css={{ srOnly: true }}>Send</styled.span>
          </InputGroupButton>
        </InputGroupAddon>
      </InputGroup>
    </styled.div>
  );
}

Empty

Processing your request
Please wait while we process your request. Do not refresh the page.
import { Button } from "@/components/ui/button";
import {
  Empty,
  EmptyContent,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from "@/components/ui/empty";
import { Spinner } from "@/components/ui/spinner";

export default function SpinnerEmpty() {
  return (
    <Empty css={{ w: "full" }}>
      <EmptyHeader>
        <EmptyMedia variant="icon">
          <Spinner />
        </EmptyMedia>
        <EmptyTitle>Processing your request</EmptyTitle>
        <EmptyDescription>
          Please wait while we process your request. Do not refresh the page.
        </EmptyDescription>
      </EmptyHeader>
      <EmptyContent>
        <Button variant="outline" size="sm">
          Cancel
        </Button>
      </EmptyContent>
    </Empty>
  );
}

Item

Use the spinner inside <ItemMedia> to indicate a loading state.

Downloading...

129 MB / 1000 MB

import { styled } from "styled-system/jsx";
import { Button } from "@/components/ui/button";
import {
  Item,
  ItemActions,
  ItemContent,
  ItemDescription,
  ItemFooter,
  ItemMedia,
  ItemTitle,
} from "@/components/ui/item";
import { Progress } from "@/components/ui/progress";
import { Spinner } from "@/components/ui/spinner";

export default function SpinnerItem() {
  return (
    <styled.div css={{ display: "flex", w: "full", maxW: "md", flexDir: "column", gap: "4" }}>
      <Item variant="outline">
        <ItemMedia variant="icon">
          <Spinner />
        </ItemMedia>
        <ItemContent>
          <ItemTitle>Downloading...</ItemTitle>
          <ItemDescription>129 MB / 1000 MB</ItemDescription>
        </ItemContent>
        <ItemActions css={{ display: "none", sm: { display: "flex" } }}>
          <Button variant="outline" size="sm" css={{ rounded: "1rem" }}>
            Cancel
          </Button>
        </ItemActions>
        <ItemFooter>
          <Progress value={75} css={{ h: "2" }} />
        </ItemFooter>
      </Item>
    </styled.div>
  );
}

API Reference

Spinner

Use the Spinner component to display a spinner.

PropTypeDefault
cssSystemStyleObject
<Spinner />