Stepper
moco/stepperFreeComponent
Render-prop step sequencer with play/pause that auto-pauses off-screen and under reduced motion.
Live preview
live · rendered by the registry
Rendered by moco on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://mocoui.site/r/stepper.jsonSource
1"use client";23import * as React from "react";4import "./stepper.css";5import { useInView, useReducedMotion } from "@/components/moco/hooks";67export interface StepperStep {8 key: string;9 caption: string;10}1112export interface StepperProps {13 steps: StepperStep[];14 render: (i: number) => React.ReactNode;15 /** Accessible name for the stepper group. */16 ariaLabel: string;17}1819/**20 * Generic state-machine stepper. Auto-play never starts on its own — it needs21 * a click — and it stops when the component scrolls out of view.22 */23export function Stepper({ steps, render, ariaLabel }: StepperProps) {24 const [i, setI] = React.useState(0);25 const [playing, setPlaying] = React.useState(false);26 const ref = React.useRef<HTMLDivElement>(null);27 const visible = useInView(ref, { once: false, rootMargin: "0px" });28 const reduced = useReducedMotion();2930 React.useEffect(() => {31 if (!playing || !visible || reduced) return;32 const t = setInterval(() => setI((v) => (v + 1) % steps.length), 1600);33 return () => clearInterval(t);34 }, [playing, visible, reduced, steps.length]);3536 React.useEffect(() => {37 if (!visible) setPlaying(false);38 }, [visible]);3940 return (41 <div42 ref={ref}43 tabIndex={0}44 role="group"45 aria-label={ariaLabel}46 onKeyDown={(e) => {47 if (e.key === "ArrowRight") {48 setPlaying(false);49 setI((v) => Math.min(steps.length - 1, v + 1));50 }51 if (e.key === "ArrowLeft") {52 setPlaying(false);53 setI((v) => Math.max(0, v - 1));54 }55 }}56 >57 <div key={i} className="moco-win-fade">58 {render(i)}59 </div>6061 <p className="moco-step-cap" aria-live="polite">62 {steps[i].caption}63 </p>6465 <div className="moco-step-bar">66 <button67 type="button"68 className="moco-step-btn"69 aria-label="Previous step"70 disabled={i === 0}71 onClick={() => {72 setPlaying(false);73 setI((v) => Math.max(0, v - 1));74 }}75 >76 ◀77 </button>78 <button79 type="button"80 className="moco-step-btn"81 aria-label="Next step"82 disabled={i === steps.length - 1}83 onClick={() => {84 setPlaying(false);85 setI((v) => Math.min(steps.length - 1, v + 1));86 }}87 >88 ▶89 </button>90 <span>91 {i + 1} / {steps.length}92 </span>93// … truncated
What it pulls in
Other registry items
Files it writes
More from moco
All 20 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Codecode | moco | Components | Free | 1 dep · 3 files | |
| Comparecompare | moco | Components | Free | no deps · 2 files | |
| Count Upcountup | moco | Components | Free | no deps · 2 files | |
| Covercover | moco | Components | Free | no deps · 2 files | |
| Diagram Kitdiagram | moco | Components | Free | no deps · 2 files | |
| Dot Griddotgrid | moco | Components | Free | no deps · 2 files | |
| Figurefigure | moco | Components | Free | no deps · 2 files | |
| Hookshooks | moco | Components | Free | no deps |
