Onboarding screen with a grid of available integrations showing connection status and connect/skip actions. Perfect for apps that rely on third-party services like Slack, GitHub, and Google.
Onboarding screen that lists available third-party integrations as a responsive grid of rows, each showing an icon, name, and a Connect action (or a "Coming soon" label for services that aren't live yet). Connecting a service toggles local state and rolls into a running " connected" summary line above the CTAs.
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://ui.beste.co/r/onboarding15?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/onboarding15?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/onboarding15.tsx and the badge and button shadcn/ui primitives it depends on.
The installed file exports onboarding15Demo alongside the block: the exact props behind the preview above. Spread it to get a working integrations step in one line.
import { Onboarding15, onboarding15Demo } from "@/components/beste/block/onboarding15";
export default function OnboardingPage() {
return <Onboarding15 {...onboarding15Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Calendar, Github, MessageSquare } from "lucide-react";
import { Onboarding15 } from "@/components/beste/block/onboarding15";
export default function OnboardingPage() {
return (
<Onboarding15
badge={{ label: "Integrations", variant: "secondary" }}
heading="Connect your tools"
description="Link the apps you already use to supercharge your workflow."
integrations={[
{ id: "slack", name: "Slack", icon: <MessageSquare className="size-5" />, status: "connected" },
{ id: "github", name: "GitHub", icon: <Github className="size-5" />, status: "available" },
{ id: "google", name: "Google Calendar", icon: <Calendar className="size-5" />, status: "available" },
]}
primaryButton={{ label: "Continue", href: "/onboarding/finish" }}
secondaryButton={{ label: "Skip for now", href: "/dashboard" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | { label: string; variant?: "default" | "secondary" | "outline" } | – | Small badge above the heading |
heading | string | – | Main headline |
description | string | – | Supporting copy below the heading |
integrations | Integration[] | [] | Grid of connectable services |
primaryButton | { label: string; href: string } | – | Primary CTA link |
secondaryButton | { label: string; href: string } | – | Secondary CTA link |
labels | { stepOf?: string; connected?: string; connect?: string; comingSoon?: string; connectedCount?: string } | – | Template strings for the step counter, button states, and connected-count summary |
currentStep | number | 1 | Current step number, used only to fill the step-of label |
totalSteps | number | 4 | Total step count, used only to fill the step-of label |
className | string | – | Extra classes for the outer <section> |
type ConnectionStatus = "connected" | "available" | "coming-soon";
type Integration = {
id: string;
name: string;
icon: React.ReactNode;
status: ConnectionStatus;
};useState<Set<string>> is seeded once at mount from every integration whose status is "connected". Clicking Connect/Connected only toggles membership in that in-memory set, it never writes back to the integrations prop, so a page refresh resets anything the user toggled during the session.status: "coming-soon" render a plain "Coming soon" text label in place of the button and can't be toggled at all.connected.size is greater than zero; when nothing is connected, an empty spacer <div> fills the same slot so the layout height doesn't jump.integrations.length: 2 or fewer becomes a centered flex row, exactly 3 becomes a 3-column grid, and 4 or more falls back to a responsive sm:grid-cols-2 lg:grid-cols-3 grid.primaryButton and secondaryButton are always-enabled plain links; unlike some sibling onboarding blocks, this screen never disables Continue while integrations remain unconnected.onboarding24
Onboarding screen displaying essential keyboard shortcuts in a grouped grid layout with key badges. Perfect for productivity tools that want to accelerate user adoption.
onboarding21
Completion screen shown after finishing onboarding with a summary of what was configured and quick-start action links. Perfect for ending the setup flow with clear next steps.
onboarding5
Multi-step progress indicator with numbered circles connected by a progress line. Perfect for account setup wizards that show users their completion status.
onboarding26
Onboarding screen with import options from other platforms, CSV upload, and manual entry. Perfect for SaaS migration flows that help users bring existing data into the platform.
onboarding14
Combined onboarding card for creating a workspace with name and URL slug, plus a team invite section with email inputs. Perfect for SaaS apps that require team collaboration setup.
onboarding23
Onboarding screen for configuring account security including two-factor authentication, recovery email, and backup codes. Perfect for apps that prioritize security during onboarding.