A team setup section pairing a soft panel with a working invite row, a role picker, and a plain-language table of what each role can reach, with a bordered list of who is already on the account and whether they have accepted, closing on a seat meter that fills one tick per seat taken.
A team setup section pairing a soft panel with a working invite row, a role picker and a plain-language table of what each role can reach, with a bordered list of who is already on the account and whether they have accepted, closing on a seat meter that fills one tick per seat taken.
Upgrade to Pro
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/onboarding37?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/onboarding37?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/onboarding37.tsx, the shadcn/ui input and select components it depends on, and the badge23 and button21 components it uses for the eyebrow and the invite action.
The installed file exports onboarding37Demo alongside the block: the exact props behind the preview above. Spread it to get a working section in one line.
import { Onboarding37, onboarding37Demo } from "@/components/beste/block/onboarding37";
export default function TeamPage() {
return <Onboarding37 {...onboarding37Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Onboarding37 } from "@/components/beste/block/onboarding37";
export default function TeamPage() {
return (
<Onboarding37
badge={{ label: "Bring the team in" }}
heading="Invite people to the job they actually do"
description="Roles are written in plain language."
form={{
emailLabel: "Work email",
emailPlaceholder: "colleague@practice.com",
roleLabel: "Their role",
roleOptions: ["Reception", "Clinician", "Practice manager"],
submitLabel: "Send the invite",
finePrint: "Invites expire after seven days.",
}}
rolesTitle="What each role can reach"
roleNotes={[
{ name: "Reception", description: "The clinic list, bookings, and messaging." },
{ name: "Finance", description: "Invoices, payments, and exports. No member records." },
]}
listTitle="Already on the account"
teammates={[
{
name: "Elena Rourke",
email: "elena@example.com",
role: "Practice manager",
state: "accepted",
avatar: { src: "/people/elena.jpg", alt: "Portrait of Elena Rourke" },
},
{ name: "Noah Reyes", email: "noah@example.com", role: "Locum", state: "pending" },
]}
stateLabels={{ accepted: "Active", pending: "Invited" }}
seats={{
label: "Seats in use",
used: 4,
total: 10,
unitLabel: "of 10 on this plan",
note: "Adding a seat mid-month is prorated.",
}}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | { label: string } | – | Eyebrow above the hairline rule, rendered through Badge23 |
heading | string | – | Section heading in the left column of the header |
description | string | – | Supporting paragraph, right-aligned from md up |
form | InviteForm | – | Labels, placeholders and role options for the invite row |
rolesTitle | string | – | Heading above the role explanations |
roleNotes | RoleNote[] | [] | What each role can reach, in plain language |
listTitle | string | – | Heading above the existing team list |
teammates | Teammate[] | [] | Who is already on the account |
stateLabels | Record<InviteState, string> | – | The word shown for accepted and pending |
seats | SeatUsage | – | Seat meter figures and its caveat |
className | string | – | Extra classes for the outer section |
type InviteState = "accepted" | "pending";
type InviteForm = {
emailLabel: string;
emailPlaceholder: string;
roleLabel: string;
roleOptions: string[];
submitLabel: string;
finePrint: string;
};
type RoleNote = {
name: string;
description: string;
};
type Teammate = {
name: string;
email: string;
role: string;
state: InviteState;
avatar?: { src: string; alt: string };
};
type SeatUsage = {
label: string;
used: number;
total: number;
unitLabel: string;
note: string;
};sm with sm:items-end, so the email field, the role select and the submit button all sit on the same bottom edge despite the labels above two of them.SelectTrigger carries data-[size=default]:h-11 rather than a plain h-11. shadcn's own data-attribute rule outranks an unqualified height class, so without the qualifier the select would render shorter than the input beside it. The submit button carries a matching h-11.avatar is optional on a teammate. Without one the block renders an initial from name.charAt(0) in a muted circle, which is what keeps a pending invite from needing a photograph.state is shown as a word in emerald or muted, never as colour alone.seats.total ticks and fills the first seats.used, so the meter is generated from the numbers rather than from a percentage. A used above total simply fills every tick.aria-hidden, since the figure and unit label above it carry the same information as text.mt-auto inside a flex flex-col card, so it pins to the bottom of the column regardless of how many teammates are listed.onSubmit, so the invite call is wired by the integrator.Wiring the form up
The invite row renders its fields and leaves submission to you. For validation, error states and submit handling, the patterns in React Hook Form, TanStack Form, and Formisch cover this shape of form, including the select.
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.
onboarding34
A getting-started section whose role pills swap a sticky summary column and the numbered steps beside it, each step carrying its own title, explanation, and honest time estimate.
onboarding33
A setup panel pairing a soft progress column, where an oversized percentage and accent bar react to what is ticked, with hairline checklist rows that each carry a description and a jump-in link.
onboarding43
A two-column setup section: the pitch and what each answer changes on the left, and a one-question-at-a-time wizard on the right that ends in a review of everything it is about to create.