Kosmesis
Components

Spinner

A loading indicator, wrapping Morphos's Spinner primitive.

Installation

npx kosmesis add spinner
pnpm dlx kosmesis add spinner
yarn dlx kosmesis add spinner
bunx kosmesis add spinner

Install the following dependencies:

npm install @morphos/feedback
pnpm add @morphos/feedback
yarn add @morphos/feedback
bun add @morphos/feedback

Copy and paste the following code into your project.

spinner.tsx
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import { Spinner as MorphosSpinner, type SpinnerProps as MorphosSpinnerProps  } from "@morphos/feedback";import { cn } from "@/lib/utils";export type SpinnerProps = MorphosSpinnerProps;/** * Morphos's `Spinner` sets `role="status"`/`aria-busy` but renders no visual content itself * (it's an empty `<span>`) — the spin animation and icon are pure CSS/SVG background here. */@Component()export class Spinner extends StatelessComponent<SpinnerProps> {  render() {    const { class: cls, ...rest } = this.props;    return (      <MorphosSpinner        class={cn(          "inline-block size-4 animate-spin rounded-full border-2 border-current border-t-transparent text-muted-foreground",          cls,        )}        {...rest}      />    );  }}

Install the following dependencies:

npm install @morphos/feedback @praxisjs/css
pnpm add @morphos/feedback @praxisjs/css
yarn add @morphos/feedback @praxisjs/css
bun add @morphos/feedback @praxisjs/css

Copy and paste the following code into your project.

spinner.tsx
import { StatelessComponent } from "@praxisjs/core";import { cx, keyframes, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import { Spinner as MorphosSpinner, type SpinnerProps as MorphosSpinnerProps  } from "@morphos/feedback";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);const spin = keyframes("kosmesis-spin", { from: { transform: "rotate(0deg)" }, to: { transform: "rotate(360deg)" } });class SpinnerStyles extends Stylesheet {  $root = this.css({    display: "inline-block",    width: "1rem",    height: "1rem",    borderRadius: "9999px",    border: "2px solid currentColor",    borderTopColor: "transparent",    color: t.mutedForeground,    animation: `${spin} 0.75s linear infinite`,  });}export type SpinnerProps = MorphosSpinnerProps;/** * Morphos's `Spinner` sets `role="status"`/`aria-busy` but renders no visual content itself * (it's an empty `<span>`) — the spin animation and icon are pure CSS/SVG background here. */@Component()export class Spinner extends StatelessComponent<SpinnerProps> {  @Styled(SpinnerStyles) $s!: SpinnerStyles;  render() {    const { class: cls, ...rest } = this.props;    return <MorphosSpinner class={cx(this.$s.$root, cls)} {...rest} />;  }}

Examples

Usage

import { Spinner } from "@/components/ui/spinner";
import { Button } from "@/components/ui/button";

<Spinner />
<Button disabled>
  <Spinner class="mr-2 size-4" /> Please wait
</Button>

On this page