Components
Progress
A progress bar with an indeterminate mode, wrapping Morphos's Progress primitive.
Installation
npx kosmesis add progresspnpm dlx kosmesis add progressyarn dlx kosmesis add progressbunx kosmesis add progressInstall the following dependencies:
npm install @morphos/feedbackpnpm add @morphos/feedbackyarn add @morphos/feedbackbun add @morphos/feedbackCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { Component } from "@praxisjs/decorators";import { Progress as MorphosProgress, type ProgressProps as MorphosProgressProps } from "@morphos/feedback";import { cn } from "@/lib/utils";export type ProgressProps = MorphosProgressProps;/** * Morphos's `Progress` sets `role="progressbar"` and the `--progress` custom property on the * same root element (it does not render children), so the ARIA element doubles as the visual * fill here — wrapped in a track `div` for the background/rounding. */@Component()export class Progress extends StatelessComponent<ProgressProps> { render() { const { class: cls, ...rest } = this.props; return ( <div class={cn("relative h-2 w-full overflow-hidden rounded-full bg-primary/20", cls)}> <MorphosProgress class="block h-full w-(--progress,0%) origin-left bg-primary transition-all data-indeterminate:w-1/3 data-indeterminate:animate-pulse" {...rest} /> </div> ); }}Install the following dependencies:
npm install @morphos/feedback @praxisjs/csspnpm add @morphos/feedback @praxisjs/cssyarn add @morphos/feedback @praxisjs/cssbun add @morphos/feedback @praxisjs/cssCopy and paste the following code into your project.
import { StatelessComponent } from "@praxisjs/core";import { cx, keyframes, Stylesheet, Styled, tokenVars } from "@praxisjs/css";import { Component } from "@praxisjs/decorators";import { Progress as MorphosProgress, type ProgressProps as MorphosProgressProps } from "@morphos/feedback";import { KosmesisTokens } from "@/lib/kosmesis-theme";const t = tokenVars(KosmesisTokens);const pulse = keyframes("kosmesis-pulse", { "0%, 100%": { opacity: "1" }, "50%": { opacity: "0.5" } });class ProgressStyles extends Stylesheet { $track = this.css({ position: "relative", height: "0.5rem", width: "100%", overflow: "hidden", borderRadius: "9999px", backgroundColor: `color-mix(in oklab, ${t.primary} 20%, transparent)`, }); $fill = this.css({ display: "block", height: "100%", width: "var(--progress, 0%)", transformOrigin: "left", backgroundColor: t.primary, transition: "width 200ms ease", }).on("&[data-indeterminate]", { width: "33%", animation: `${pulse} 2s cubic-bezier(0.4, 0, 0.6, 1) infinite` });}export type ProgressProps = MorphosProgressProps;/** * Morphos's `Progress` sets `role="progressbar"` and the `--progress` custom property on the * same root element (it does not render children), so the ARIA element doubles as the visual * fill here — wrapped in a track `div` for the background/rounding. */@Component()export class Progress extends StatelessComponent<ProgressProps> { @Styled(ProgressStyles) $s!: ProgressStyles; render() { const { class: cls, ...rest } = this.props; return ( <div class={cx(this.$s.$track, cls)}> <MorphosProgress class={this.$s.$fill} {...rest} /> </div> ); }}Examples
Usage
import { Progress } from "@/components/ui/progress";
<Progress value={66} />
<Progress /> {/* indeterminate — no value prop */}Props
| Prop | Type | Default |
|---|---|---|
value | number | undefined | — (indeterminate when omitted) |
max / min | number | 100 / 0 |
Morphos's Progress sets role="progressbar" and the --progress custom property on its own
root element rather than rendering a separate indicator child — Kosmesis wraps it in a track
div for the background, and the fill itself is the Morphos element, sized via
w-(--progress,0%).