Invite chooser

Pro

Shown at sign-in when more than one account has invited you. Pick one to join; the others are superseded and will show as expired. Or create your own account instead, which supersedes them all. Nothing happens until you choose.

Markdown

Preview

Install

With the Candor CLI

First time? Get started sets up the registry and theme. Or with shadcn directly: npx shadcn@latest add @candor/invite-chooser

Brings in: button, locale, relative-time, utils · npm: lucide-react@^1.67.0

Usage

TSX · The example above
"use client"

import { InviteChooser, type IncomingInvite } from "@/components/invite-chooser"

const inDays = (d: number) => new Date(Date.now() + d * 86_400_000).toISOString()

const invites: IncomingInvite[] = [
  { id: "inv-1", account: "Acme", invitedBy: "Priya", grants: ["Contributor on Acme API Staging"], expiresAt: inDays(5) },
  { id: "inv-2", account: "Acme Labs", invitedBy: "Dana", grants: [], expiresAt: inDays(1) },
]

export default function Example() {
  // Nothing is chosen until the person picks an invite.
  return <InviteChooser invites={invites} onJoin={() => {}} onCreateOwn={() => {}} />
}

<InviteChooser>

PropTypeDefaultDescription
invitesrequiredIncomingInvite[]—The invites waiting for this person, one per account.
onJoinrequired(id: string) => void—Called with the chosen invite's id when the person joins.
onCreateOwn(() => void) | undefined—Shows a link to create their own account instead; called when it's clicked.
busyboolean | undefinedfalseDisables Join while it's being recorded.
classNamestring | undefined—Extra classes for the outer element.

Strings

The fixed words, in English by default. Change any of them under inviteChooser in <LocaleProvider strings={{ … }}>; the table is exported as inviteChooserStrings.

KeyEnglish
heading{ one: "{count} account has invited you", other: "{count} accounts have invited you" }
belongToOne{ one: "You can belong to one. Joining it supersedes the other invite.", other: "You can belong to one. Joining it supersedes the other invites.", }
fromFrom {name} · expires {expires}
noRolesNo roles yet
joinJoin {account}
chooseChoose an account
createOwnCreate my own account instead

Types

IncomingInvite
{ id: string account: string invitedBy: string /** What joining gives, e.g. ["Editor on Shop staging"]. */ grants: string[] expiresAt: string }