Componentfeedback0.7 KB gzipZero dependencies
Save Indicator
Auto-save status chip: idle, saving, saved, error states.
Preview
Live Preview
✓ Saved
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add save-indicatorOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { SaveIndicator } from "@/components/ui/save-indicator";
<SaveIndicator />Usage guidance
Use Save Indicator when a ticket stub surface needs Auto-save status chip: idle, saving, saved, error states. Keep props minimal and prefer composition with sibling stubs.
Avoid Save Indicator for long form flows or dense data grids where a dedicated layout block fits better.
Source code
save-indicator.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface SaveIndicatorProps extends React.HTMLAttributes<HTMLSpanElement> {
/** idle | saving | saved | error */
status?: "idle" | "saving" | "saved" | "error";
label?: string;
}
/** Autosave state indicator: smooth state transitions with checkmark. */
export function SaveIndicator({ status = "idle", label, className, ...props }: SaveIndicatorProps) {
const meta: Record<string, { text: string; tone: string; icon: React.ReactNode }> = {
idle: { text: "Saved", tone: "text-muted-foreground", icon: <span className="size-1.5 rounded-full bg-border" /> },
saving: { text: "Saving…", tone: "text-muted-foreground", icon: <span className="size-2.5 rounded-full border-2 border-border border-t-accent animate-spin motion-reduce:animate-none" /> },
saved: { text: "✓ Saved", tone: "text-success", icon: <span className="size-1.5 rounded-full bg-success animate-pulse motion-reduce:animate-none" /> },
error: { text: "Save failed", tone: "text-destructive", icon: <span className="size-1.5 rounded-full bg-destructive animate-pulse motion-reduce:animate-none" /> },
};
const m = meta[status];
return (
<span
className={cn(
"inline-flex items-center gap-1.5 rounded-full border border-border bg-card px-2 py-0.5 font-mono text-[10px] uppercase tracking-wider",
"transition-all duration-300 motion-reduce:transition-none",
m.tone,
className
)}
role="status"
aria-live="polite"
{...props}
>
{m.icon}
{label ?? m.text}
</span>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| status | "idle" | "saving" | "saved" | "error" | idle | saving | saved | error |
| label | string |