Start Building in Minutes
Follow these three simple steps to integrate our powerful SDK into your application.
Install the Package
Start by installing the artifact-ui package using your preferred package manager. It's lightweight and fully typed.
Configure Theme
Add the tailwind plugin to your configuration file to enable the custom animations and utilities.
Import Components
You're all set! Import any component and start building your dream interface in minutes.
npm install artifact-ui
# or
pnpm add artifact-ui
# or
yarn add artifact-uiInstallation
Install dependencies
npm install framer-motion lucide-reactCopy and paste the following code into your project.
"use client";
import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import { cn } from "@/lib/utils";
import { Check, ChevronRight, Copy } from "lucide-react";
interface Step {
id: string;
title: string;
description: string;
code?: string;
image?: string;
}
interface OnboardingStepsProps {
steps: Step[];
title?: string;
description?: string;
ctaText?: string;
ctaLink?: string;
className?: string;
}
export function OnboardingSteps({
steps,
title = "How it works",
description = "Get up and running in minutes with our simple onboarding process.",
ctaText = "Get Started",
ctaLink = "#",
className,
}: OnboardingStepsProps) {
const [activeStep, setActiveStep] = useState(0);
const [copied, setCopied] = useState(false);
const handleCopy = (code: string) => {
navigator.clipboard.writeText(code);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};
return (
<div
className={cn(
"w-full max-w-6xl mx-auto p-6 md:p-12 font-sans",
className,
)}
>
<div className="text-center mb-20 space-y-4">
<h2 className="text-4xl md:text-5xl font-bold tracking-tight text-foreground">
{title}
</h2>
<p className="text-muted-foreground text-lg max-w-2xl mx-auto">
{description}
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-2 gap-16 items-start">
{/* Left Column: Steps List */}
<div className="space-y-4 relative pl-4">
{/* Continuous Vertical Line */}
<div className="absolute left-[59px] top-0 bottom-0 w-[2px] bg-white/10 hidden md:block" />
{/* Active Progress Line */}
<motion.div
className="absolute left-[59px] top-0 w-[2px] bg-white hidden md:block origin-top"
initial={{ height: 0 }}
animate={{ height: `${(activeStep / (steps.length - 1)) * 100}%` }}
transition={{ duration: 0.5, ease: "easeInOut" }}
/>
{steps.map((step, index) => (
<div
key={step.id}
className={cn(
"relative flex gap-8 p-6 rounded-3xl transition-all duration-300 cursor-pointer border border-transparent group",
activeStep === index
? "bg-white/5 border-white/10 shadow-[0_0_30px_-10px_rgba(255,255,255,0.1)] backdrop-blur-sm"
: "hover:bg-white/5 border-transparent",
)}
onClick={() => setActiveStep(index)}
>
{/* Step Indicator */}
<div className="relative z-10 flex-shrink-0 mt-1">
<div
className={cn(
"w-10 h-10 rounded-full flex items-center justify-center text-sm font-bold border-2 transition-all duration-300",
activeStep === index
? "bg-white border-white text-black scale-110 shadow-[0_0_20px_-5px_rgba(255,255,255,0.5)]"
: index < activeStep
? "bg-white border-white text-black"
: "bg-[#0f1117] border-white/20 text-white/40 group-hover:border-white/40 group-hover:text-white/60",
)}
>
{index < activeStep ? (
<Check className="w-5 h-5" />
) : (
<span>{index + 1}</span>
)}
</div>
</div>
{/* Step Content */}
<div className="space-y-3 pt-1">
<h3
className={cn(
"text-xl font-bold transition-colors",
activeStep === index
? "text-foreground"
: "text-muted-foreground group-hover:text-foreground/80",
)}
>
{step.title}
</h3>
<p className="text-muted-foreground leading-relaxed text-base">
{step.description}
</p>
</div>
</div>
))}
</div>
{/* Right Column: Interactive Preview / Code */}
<div className="relative lg:sticky lg:top-8">
<div className="relative rounded-2xl overflow-hidden border border-white/10 bg-[#0f1117] shadow-2xl min-h-[400px]">
{/* Window Controls */}
<div className="flex items-center justify-between px-6 py-4 border-b border-white/5 bg-white/[0.02]">
<div className="flex items-center gap-2">
<div className="w-3 h-3 rounded-full bg-[#FF5F56]" />
<div className="w-3 h-3 rounded-full bg-[#FFBD2E]" />
<div className="w-3 h-3 rounded-full bg-[#27C93F]" />
</div>
<div className="text-xs font-medium text-white/20 font-mono">
{steps[activeStep].id}.tsx
</div>
</div>
{/* Content Area */}
<div className="relative p-6 h-full min-h-[340px] flex flex-col">
<AnimatePresence mode="wait">
<motion.div
key={activeStep}
initial={{ opacity: 0, y: 10, filter: "blur(4px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
exit={{ opacity: 0, y: -10, filter: "blur(4px)" }}
transition={{ duration: 0.3 }}
className="h-full"
>
{steps[activeStep].code ? (
<div className="relative group h-full">
<button
onClick={() => handleCopy(steps[activeStep].code!)}
className="absolute right-0 top-0 p-2 rounded-lg bg-white/5 text-white/40 opacity-0 group-hover:opacity-100 transition-all hover:bg-white/10 hover:text-white"
>
{copied ? (
<Check className="w-4 h-4" />
) : (
<Copy className="w-4 h-4" />
)}
</button>
<pre className="font-mono text-sm leading-relaxed text-blue-100/90 overflow-x-auto p-2">
<code>{steps[activeStep].code}</code>
</pre>
</div>
) : (
<div className="h-full flex items-center justify-center">
{steps[activeStep].image ? (
// eslint-disable-next-line @next/next/no-img-element
<img
src={steps[activeStep].image}
alt={steps[activeStep].title}
className="w-full h-full object-cover rounded-lg"
/>
) : (
<div className="text-center p-8 text-white/20">
<div className="w-16 h-16 border-2 border-dashed border-white/10 rounded-xl flex items-center justify-center mx-auto mb-4">
<span className="text-2xl font-bold">
{activeStep + 1}
</span>
</div>
<p>No preview available</p>
</div>
)}
</div>
)}
</motion.div>
</AnimatePresence>
</div>
</div>
{/* Decorative Glow */}
<div className="absolute -inset-4 bg-primary/20 blur-3xl -z-10 rounded-[3rem] opacity-20" />
</div>
</div>
{/* Bottom CTA */}
<div className="mt-20 text-center">
<a
href={ctaLink}
className="inline-flex items-center justify-center px-8 py-4 text-lg font-semibold text-primary-foreground bg-primary rounded-full hover:bg-primary/90 transition-all hover:scale-105 shadow-[0_0_40px_-10px_var(--primary)] group"
>
{ctaText}
<ChevronRight className="ml-2 w-5 h-5 group-hover:translate-x-1 transition-transform" />
</a>
</div>
</div>
);
}Update the import paths to match your project setup.
Features
- ✅ Interactive Progress - Smooth vertical progress line that tracks the active step
- ✅ Code Snippets - Built-in code block display with copy functionality
- ✅ Visual Previews - Support for images or code per step
- ✅ Premium Design - Glassmorphism effects, glow animations, and clean typography
- ✅ Responsive Layout - Stacks elegantly on mobile devices
- ✅ Customizable - Easy to style with Tailwind CSS classes
- ✅ Accessible - Keyboard navigation and semantic structure
Usage
Basic Usage
import OnboardingSteps from "@/components/ui/onboarding-steps";
const steps = [
{
id: "step-1",
title: "Sign Up",
description: "Create your account in seconds.",
image: "/images/signup.png",
},
{
id: "step-2",
title: "Connect Data",
description: "Link your data sources securely.",
image: "/images/connect.png",
},
];
export default function Page() {
return (
<OnboardingSteps
steps={steps}
title="Get Started"
description="Follow these simple steps."
/>
);
}With Code Snippets
Perfect for developer tools and API documentation.
const devSteps = [
{
id: "install",
title: "Installation",
description: "Install the package via npm.",
code: "npm install my-awesome-package"
},
{
id: "config",
title: "Configuration",
description: "Add your API key to the config.",
code: "export const config = { apiKey: '...' }"
}
]
<OnboardingSteps steps={devSteps} />Props
OnboardingStepsProps
| Prop | Type | Description | Default |
|---|---|---|---|
steps | Step[] | Array of steps to display. | Required |
title | string | Title of the section. | "How it works" |
description | string | Description of the section. | "Get up and running in minutes..." |
ctaText | string | Text for the Call to Action button. | "Get Started" |
ctaLink | string | Link for the Call to Action button. | "#" |
className | string | Additional CSS classes for the container. | - |
Step Interface
interface Step {
id: string;
title: string;
description: string;
code?: string; // Optional: Code to display in the window
image?: string; // Optional: Image URL to display if no code is provided
}Use Cases
Perfect for:
- SaaS Onboarding: Guide users through account setup.
- Developer Documentation: Show how to install and use your SDK.
- Feature Walkthroughs: Explain complex features step-by-step.
- Process Explanation: Visualize a multi-stage process (e.g., "How it works").
Common Patterns
Full Page Onboarding
For a dedicated onboarding page, center the component and add a max-width.
<div className="min-h-screen bg-background flex items-center justify-center py-20">
<OnboardingSteps className="max-w-5xl" steps={steps} />
</div>Modal / Dialog
You can wrap the component in a Dialog for a popup guide.
<Dialog>
<DialogContent className="max-w-4xl bg-background/95 backdrop-blur-xl">
<OnboardingSteps steps={steps} />
</DialogContent>
</Dialog>Customization
Changing Colors
The component uses Tailwind's primary and muted colors by default. You can override these in your tailwind.config.js or by passing a className to the component.
// Example: Custom blue theme
<OnboardingSteps className="[--primary:theme(colors.blue.500)]" steps={steps} />Adjusting Layout
The component uses a grid layout that switches to a single column on mobile. You can adjust the gap and padding via the className prop.
<OnboardingSteps className="max-w-7xl gap-20" steps={steps} />Examples
API Integration Guide
const apiSteps = [
{
id: "auth",
title: "Authentication",
description: "Get your API key from the dashboard.",
code: "const client = new Client({ apiKey: 'sk_...' })",
},
{
id: "request",
title: "Make a Request",
description: "Fetch data from our endpoints.",
code: "await client.users.list()",
},
];SaaS Onboarding Flow
const saasSteps = [
{
id: "invite",
title: "Invite Team",
description: "Add your team members to collaborate.",
image: "/onboarding/invite-team.png",
},
{
id: "setup",
title: "Setup Workflow",
description: "Define your first automation workflow.",
image: "/onboarding/workflow.png",
},
];