Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Invite Team Dialog Block for React

A crew page with its bulk invite dialog shown open: a pasted list becomes one chip per address with bad ones flagged, one role for the batch, a seat meter that refuses a batch that does not fit, and a Pending tab with Resend, Revoke and Undo.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Bring a whole crew in at once, with this bulk invite dialog for React with Base UI. It opens from the Crew page of Rotaloft, a shift scheduler: the page's header holds an outline Invite people Button, and the crew table, four people, the invitations waiting and a chip that counts seats, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The Dialog has two Tabs. Invite takes a pasted list, with commas, spaces or new lines between the addresses, and turns it into one chip each; an address that can't be sent keeps its chip, dashed, with its reason, such as "missing @". One Native Select sets the role for the whole batch, and a seat bar says "7 in use + 2 new of 10" and hatches what does not fit. Pending lists each waiting invitation with Resend and Revoke on the row, and an Undo line under the list. Send 2 invitations, the only Shine Button, sends the good addresses and leaves the flagged ones in the box. For preview the dialog is drawn open in place when the page loads; the Invite people button opens the real Dialog, with the same box and list. For team, shift and workspace tools with seats to spend.

FAQ

Why is the dialog already open, and what do I keep?

So you can see it without a click. On load the dialog is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The Invite people button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same TeamFields component and share the block's state, so what you pasted in the copy is there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.

How does the list become chips?

A comma, a space, a semicolon, a new line, Enter, leaving the box or a paste commits what you typed: it is split on those marks, lower-cased and added as chips. Each chip is judged against the rest: no at sign, not an address, listed twice, already on the crew or already invited. A flagged chip is dashed, carries a destructive icon and its reason in words, and can be removed with its own button, or with Backspace in an empty box. Enter in a box with nothing typed sends, as it does in any form.

What does the seat bar do?

It adds the seats in use (the crew and the invitations waiting) to the new ones and compares them with SEATS. A batch that fits fills the bar; one that doesn't is hatched past the cut, and Send says "Not enough seats: remove 1 address." and keeps the dialog open, with focus in the box. Only the good addresses count as new, so a flagged chip never costs a seat. Send is quiet and pressable while nothing can be sent, and says why.

How do Resend, Revoke and Undo work?

Resend marks the invitation as sent in this demo and says so; nothing is emailed. Revoke takes the row away, moves focus to the next row's Revoke (or to Undo when none is left), and keeps the invitation so Undo can put it back in the same place. The seat chip on the drawn page moves with each change. The Undo button is always there and quiet while there is nothing to undo.

What stays local in the demo, and how do I wire it up?

All of it. The crew, the plan's ten seats and the three waiting invitations are typed constants, and Send only adds Pending rows and says in a polite message that nothing was emailed. In your app post the good addresses and the role from send, add the rows from the response, and let your server be the judge of seats and duplicates: it knows what changed since the page loaded.

Is it accessible from the keyboard?

Yes. The real dialog is named by its title and described by its sentence, focus starts in the address box and stays inside until it closes, and Escape, Cancel and the close button return focus to Invite people. The tabs move with the arrow keys. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. The copy shown on load moves no focus; Escape inside it, Cancel and its close button close it and put focus on the button.

  • Pro

    Invite Members Dialog

    Share and invite

    A household calendar's Members page with its invite dialog shown open: one email field that knows the household's domain, so an outside address joins as a guest, the people who already have access, and a Send invite button that adds a pending row.

  • Pro

    Contact Picker Dialog

    Pickers and search

    A compose window with its recipient picker shown open: a search over fourteen contacts, four recent ones as toggles, an alphabetical list with pinned letters, a To panel of removable chips, and an Add recipients button that fills the message's To line.

  • Pro

    Seats on a team plan: members with a role each (viewers are free), a stepper for the seats you pay for, and the monthly and prorated cost worked out before you save.

  • Pro

    Team Members Settings

    Team and roles

    A members panel with seat and two-factor meters, a native table with row selection, a role menu per person and, pinned at the foot, a bulk role change and Remove that an Undo walks back one step at a time.

  • Pro

    A centred card-in-card CTA with a tags input of teammate emails that stops at the seats a plan has left, ten seat dots that fill as you add chips and a Shine Button that counts the invites.

  • Pro

    A family notes app's account page with a side sheet of signed-in devices shown open: this device pinned first, Sign out that asks inside the same row, and one button that signs out of all the others the same way.