Live Preview Wizard
A two-column onboarding layout with a stepped form on the left and a live preview canvas on the right — input morphs into the preview instantly, and step changes slide the form directionally while the preview cross-fades.
npx shadcn@latest add https://webberui.com/r/live-preview-wizard.jsonPlayground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<LivePreviewWizard />
Installation
npx shadcn@latest add https://webberui.com/r/live-preview-wizard.jsonOr, once registries are configured in components.json, install it as @webberui/live-preview-wizard.
Usage
Declare each step's form fields with <LivePreviewWizardStep>, and supply the right-hand live preview through preview. Fields inside a step read and write the shared values through useLivePreviewWizard, so input is reflected in the preview instantly.
import {
LivePreviewWizard,
LivePreviewWizardStep,
useLivePreviewWizard,
} from "@/components/ui/live-preview-wizard";
type Form = {
name: string;
};
function NameField() {
const { values, setValue } = useLivePreviewWizard<Form>();
return (
<input
value={values.name}
onChange={(e) => setValue("name", e.target.value)}
/>
);
}
function Preview() {
const { values } = useLivePreviewWizard<Form>();
return <h1>{values.name || "Your product"}</h1>;
}
export function Example() {
return (
<LivePreviewWizard<Form>
defaultValues={{ name: "" }}
preview={<Preview />}
onComplete={(values) => console.log(values)}
>
<LivePreviewWizardStep label="Brand">
<NameField />
</LivePreviewWizardStep>
</LivePreviewWizard>
);
}Props
LivePreviewWizard
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Step declarations, all <LivePreviewWizardStep> |
preview | ReactNode | (ctx) => ReactNode | — | Default live preview content, used when a step does not supply its own |
values | T | — | Controlled form data; when omitted, the component manages it internally (uncontrolled) |
defaultValues | T | {} | Initial data in uncontrolled mode |
onValuesChange | (values: T) => void | — | Fires when the data changes, with the latest complete data |
step | number | — | Controlled current step index; when omitted, the component manages it internally |
defaultStep | number | 0 | Initial step in uncontrolled mode |
onStepChange | (step, direction) => void | — | Fires when the step changes (direction: 1 forward, -1 back) |
onComplete | (values: T) => void | — | Fires when "Complete" is pressed on the last step |
progress | "dots" | "bar" | false | "dots" | Progress indicator style; false hides it |
controls | boolean | true | Whether to render the built-in back / next control bar |
previewSide | "left" | "right" | "right" | Which side the preview canvas sits on for wide screens |
previewLabel | string | "preview.app" | Text in the preview frame's faux address bar |
backLabel / nextLabel / completeLabel | string | 上一步 / 下一步 / 完成 | Control bar button text |
className | string | — | Appended to the outer grid's className |
LivePreviewWizardStep
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Step title shown in the progress indicator |
children | ReactNode | — | This step's form fields |
preview | ReactNode | (ctx) => ReactNode | — | Preview specific to this step, overriding the container's preview |
className | string | — | Appended to the step container's className |
useLivePreviewWizard<T>()
Returns the current values, setValue(key, value), setValues(partial), plus navigation state such as step / total / direction / isFirst / isLast / goTo / next / back. It must be called inside <LivePreviewWizard>.
How it works
- Both modes:
valuesandstepeach support controlled (pass the prop) and uncontrolled (defaultValues/defaultStep) usage. - Live morph: fields write into the shared
valuesthroughsetValue, and the preview repaints instantly within the same step; for color changes, pair it with CSStransition-colorsto make the morph smoother. - Direction aware:
next/back/goToderive the switch direction, so the form slides horizontally and the preview cross-fades. - Per-step preview: setting
previewon a<LivePreviewWizardStep>lets different steps emphasize different things, cross-fading naturally as you move between them.
Accessibility
- The progress dots / bar carry
roleandaria-*attributes; steps you have already reached are clickable to jump to, and the ones you have not are disabled. - Step blocks carry
aria-roledescription="步驟"(step) and anaria-label, and the current step is announced througharia-live="polite". - The preview canvas carries
aria-label="即時預覽"(live preview); the control bar buttons are all keyboard operable and have focus styling. - When the user has "reduce motion" enabled, the slide becomes a fade in / fade out and the spring transitions are disabled, with no impact on the layout structure.