Componentform1.03 KB gzipZero dependencies
Invite Team
Email plus role picker with log.
Preview
Live Preview
Invite team
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add invite-teamOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { InviteTeam } from "@/components/ui/invite-team";
<InviteTeam />Usage guidance
Use Invite Team when a ticket stub surface needs Email plus role picker with log. Keep props minimal and prefer composition with sibling stubs.
Avoid Invite Team for long form flows or dense data grids where a dedicated layout block fits better.
Source code
invite-team.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface InviteTeamProps extends React.HTMLAttributes<HTMLDivElement> {
onInvite?: (email: string, role: string) => void;
}
/** Invite team stub: email plus role chip picker with sent log. */
export function InviteTeam({ onInvite, className, ...props }: InviteTeamProps) {
const [email, setEmail] = React.useState("");
const [role, setRole] = React.useState("Member");
const [sent, setSent] = React.useState<string[]>([]);
const invite = () => { if (!email.includes("@")) return; setSent((s) => [...s, email]); onInvite?.(email, role); setEmail(""); };
return (
<div className={cn("w-full max-w-sm rounded-lg border border-border bg-card p-4", className)} {...props}>
<span className="font-mono text-[10px] uppercase tracking-[0.15em] text-muted-foreground">Invite team</span>
<div className="mt-2 flex gap-1.5">
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
onKeyDown={(e) => { if (e.key === "Enter") invite(); }}
placeholder="teammate@arena.com"
aria-label="Teammate email"
className="min-w-0 flex-1 rounded-md border border-dashed border-border bg-background px-2.5 py-1.5 font-mono text-xs text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
/>
<button type="button" onClick={invite} className="shrink-0 rounded-md bg-primary px-3 py-1.5 font-mono text-[11px] font-bold uppercase text-primary-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring">Invite</button>
</div>
<div className="mt-2 flex gap-1.5" role="group" aria-label="Role">
{["Admin", "Member", "Viewer"].map((r) => (
<button
key={r}
type="button"
aria-pressed={role === r}
onClick={() => setRole(r)}
className={cn("rounded-full border px-2 py-0.5 font-mono text-[10px] uppercase focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", role === r ? "border-accent bg-accent/10 text-accent" : "border-dashed border-border text-muted-foreground")}
>
{r}
</button>
))}
</div>
{sent.length > 0 && (
<ul className="mt-2 space-y-1">
{sent.map((s) => (
<li key={s} className="font-mono text-[11px] text-muted-foreground">Sent to {s} as {role}</li>
))}
</ul>
)}
</div>
);
}