blockmotion
Steps (motion)
The steps, appearing in order. Here the order of the animation matches the meaning.
Open in v0 (opens in a new tab)
This is the animated version of Steps. The static version looks the same with JavaScript turned off.
Preview
Installation
pnpm dlx shadcn@latest add https://facadeui.dev/r/steps-motion.jsonThis component needs motion-primitives, steps. The CLI installs them for you.
Usage
This is the code for the preview above. To install it as a file, run npx shadcn@latest add @facade/steps-motion-demo.
"use client"
/**
* The `steps` demo, with the motion variant swapped in.
*
* Identical props: the motion variant only changes which slot components
* the static section renders through.
*
* `"use client"` is required here, not incidental: the motion variant is a
* client component, and icon components cannot cross a server-to-client
* boundary as props. See the note on `IconComponent`.
*/
import { StepsMotion } from "@registry/sections/steps-motion"
import { STEPS } from "./content"
export function Demo() {
return (
<StepsMotion
eyebrow="Getting started"
title="From nothing to a landing page"
description="An ordered list, so a screen reader already announces 'step 2 of 3' without the numeral being read twice."
items={STEPS}
/>
)
}Source
These are the files the CLI copies into your project.
"use client"
/**
* StepsMotion — the numbered sequence with a staggered entrance.
*
* Steps arrive in order, which is the one place a stagger carries meaning rather than decoration.
*
* A genuine wrapper: it renders the static `Steps` and only swaps the list
* slots, so no markup, styling or accessibility behaviour is duplicated.
*
* The list slot renders an `ol` rather than a `ul`, because the sequence is the
* content — which is also why the stagger belongs here at all. The item slot
* still renders an `li`: an `ol` may only contain list items, and a `div` there
* is invalid markup that axe reports as `list`.
*
* Dependencies: react, @/components/motion/slots, @/components/motion/stagger,
* @/components/sections/steps.
*/
import type { ReactNode } from "react"
import { StaggerListItem } from "@/components/motion/slots"
import { Stagger } from "@/components/motion/stagger"
import { Steps, type StepsProps } from "@/components/sections/steps"
function StaggerOl({
className,
children,
}: {
className?: string
children?: ReactNode
}) {
return (
<Stagger as="ol" className={className}>
{children}
</Stagger>
)
}
export type StepsMotionProps = Omit<StepsProps, "listAs" | "itemAs">
export function StepsMotion(props: StepsMotionProps) {
return <Steps {...props} listAs={StaggerOl} itemAs={StaggerListItem} />
}Props
StepsMotionProps
Extends Omit<StepsProps, "listAs" | "itemAs">.