Compound team invitation block with fluid morphing variant tabs, an invite form, member lists with role dropdowns, role groups, and pending invites.
npx shadcn@latest add @iconiq/team-invitation"use client";
import { Clock, ShieldCheck, UserPlus, Users } from "lucide-react";
import {
TeamInvitation,
TeamInvitationCard,
TeamInvitationDescription,
TeamInvitationHeader,
TeamInvitationInviteField,
TeamInvitationMemberList,
TeamInvitationPanel,
TeamInvitationPanels,
TeamInvitationPendingList,
TeamInvitationRoleGroups,
TeamInvitationTab,
TeamInvitationTabs,
TeamInvitationTitle,
} from "@/components/ui/team-invitation";
const members = [
{
id: "trevor",
name: "Trevor Phillips",
email: "trevorphillips@gmail.com",
role: "Assistant",
avatar: "/assets/av1.png",
},
{
id: "michael",
name: "Michael De Santa",
email: "michaeldesanta@gmail.com",
role: "Junior Level",
avatar: "/assets/av2.png",
},
{
id: "franklin",
name: "Franklin Clinton",
email: "franklinclinton@gmail.com",
role: "Senior Level",
avatar: "/assets/av3.png",
}
];
export function TeamInvitationPreview() {
return (
<TeamInvitation
defaultVariant="invite"
members={members}
onInvite={(email) => console.log("invite", email)}
onRoleChange={(id, role) => console.log(id, role)}
pendingInvites={[
{ id: "jhon", email: "jhon@wick.com", sentAt: "Sent 2d ago" },
]}
roles={["Assistant", "Junior Level", "Senior Level"]}
>
<TeamInvitationCard>
<TeamInvitationHeader icon={<Users />}>
<TeamInvitationTitle>Invite Team Member</TeamInvitationTitle>
<TeamInvitationDescription>
Share tasks with other users
</TeamInvitationDescription>
</TeamInvitationHeader>
<TeamInvitationTabs>
<TeamInvitationTab icon={<UserPlus />} value="invite">
Invite Members
</TeamInvitationTab>
<TeamInvitationTab icon={<Users />} value="manage">
Manage Team
</TeamInvitationTab>
<TeamInvitationTab icon={<ShieldCheck />} value="roles">
Role Management
</TeamInvitationTab>
<TeamInvitationTab icon={<Clock />} value="pending">
Pending Invites
</TeamInvitationTab>
</TeamInvitationTabs>
<TeamInvitationPanels>
<TeamInvitationPanel value="invite">
<TeamInvitationInviteField
buttonLabel="Invite Member"
label="Email"
/>
<TeamInvitationMemberList action="role" label="Member Lists" />
</TeamInvitationPanel>
<TeamInvitationPanel value="manage">
<TeamInvitationMemberList
action="remove"
emptyMessage="No members yet. Invite someone first."
label="Team Members"
/>
</TeamInvitationPanel>
<TeamInvitationPanel value="roles">
<TeamInvitationRoleGroups emptyMessage="No members with this role yet." />
</TeamInvitationPanel>
<TeamInvitationPanel value="pending">
<TeamInvitationPendingList
emptyMessage="No pending invites. Invite someone from the Invite Members tab."
label="Pending Invites"
/>
</TeamInvitationPanel>
</TeamInvitationPanels>
</TeamInvitationCard>
</TeamInvitation>
);
}childrenComposition surface. Place TeamInvitationCard with the header, tabs, and panels inside.
Type ReactNode
variantControlled active variant when the parent owns which panel is shown. Matches TeamInvitationTab and TeamInvitationPanel values.
Type string
defaultVariantInitial variant for uncontrolled usage.
Type string
onVariantChangeCalled when a variant tab is selected.
Type (variant: string) => void
membersSeed member list ({ id, name, email, role, avatar? }). The root keeps a working copy so role changes and removals animate locally.
Type TeamMember[]
pendingInvitesSeed pending invite list ({ id, email, sentAt? }). Invites submitted from TeamInvitationInviteField are appended here.
Type PendingInvite[]
rolesAssignable roles shown in role dropdowns and as TeamInvitationRoleGroups sections.
Type string[]
onInviteCalled with the trimmed email when the invite button is pressed or Enter is hit in the field.
Type (email: string) => void
onRoleChangeCalled when a member is assigned a new role.
Type (id: string, role: string) => void
onRemoveCalled when a member is removed.
Type (id: string) => void
onResendCalled when a pending invite's resend button is pressed.
Type (id: string) => void
onCancelInviteCalled when a pending invite is cancelled.
Type (id: string) => void
onCloseRenders the header close button and is called when it is pressed. Omit to hide the button.
Type () => void
classNameExtra classes for the outer wrapper.
Type string
valueVariant id. Selecting the tab reveals the TeamInvitationPanel with the same value.
Type string
iconIcon shown while the tab is collapsed and expanded.
Type ReactNode
childrenLabel revealed while the tab is active.
Type ReactNode
valueVariant id paired with the TeamInvitationTab of the same value.
Type string
childrenPanel content — section parts below or any custom markup.
Type ReactNode
labelSection heading rendered with TeamInvitationSectionLabel. On TeamInvitationInviteField this sits above the field row.
Type ReactNode
buttonLabelInvite button copy on TeamInvitationInviteField.
Type ReactNode
placeholderInput placeholder on TeamInvitationInviteField.
Type string
actionTrailing control per row on TeamInvitationMemberList. Defaults to role.
Type "role" | "remove" | "none"
emptyMessageDashed empty-state row shown when a list or role group has no entries. Omit to render nothing.
Type ReactNode
Structural parts that compose the card shell. Card animates in with a spring and morphs its height between variants, Header wraps an optional icon tile, your Title and Description, and the close button when onClose is set on the root. Each accepts `children` and an optional `className`.
TeamInvitationCard renders the bordered card surface with the entrance spring and fluid height morph.
TeamInvitationHeader takes an optional `icon` rendered in a bordered tile before your heading copy.
TeamInvitationSectionLabel is the shared heading used by the section parts — reuse it for your own panel content.
Install the exact registry entry shown on the right when you want the component file and its declared runtime dependencies together.
Dependencies: motion, lucide-react.
Contact
Additionally, if you find any bug or issue, feel free to raise an issue.
Share tasks with other users