Build an "invite your team" onboarding step with Tailwind CSS, max-w-xl and centred. Above the heading, a step counter and a slim two-tone progress bar. Under the subline, an add row — an email field and a dark Add button side by side — plus a hidden inline error line and a hint that several addresses can be pasted at once. Below that, an empty list container for the invitees and a dashed empty-state panel saying nobody has been added yet. Each invitee row should render as an avatar circle with initials, the address, a role select (Admin, Member, Viewer), and a ✕ remove button. Finish with a footer row: a muted "I'll do this later" link on the left and a dark Continue button on the right. Then add JavaScript that splits pasted input on commas, semicolons and spaces, validates each address and shows the error for bad ones, ignores duplicates already in the list, derives the initials from the address, appends the row with a working remove button, swaps the empty state out once there is at least one invitee, and rewrites the Continue label to "Send 3 invites" or plain "Continue" depending on the count.
Build an "invite your team" onboarding step with Tailwind CSS, max-w-xl and centred. Above the heading, a step counter and a slim two-tone progress bar. Under the subline, an add row — an email field and a dark Add button side by side — plus a hidden inline error line and a hint that several addresses can be pasted at once. Below that, an empty list container for the invitees and a dashed empty-state panel saying nobody has been added yet. Each invitee row should render as an avatar circle with initials, the address, a role select (Admin, Member, Viewer), and a ✕ remove button. Finish with a footer row: a muted "I'll do this later" link on the left and a dark Continue button on the right. Then add JavaScript that splits pasted input on commas, semicolons and spaces, validates each address and shows the error for bad ones, ignores duplicates already in the list, derives the initials from the address, appends the row with a working remove button, swaps the empty state out once there is at least one invitee, and rewrites the Continue label to "Send 3 invites" or plain "Continue" depending on the count.
<div class="mx-auto max-w-xl px-6 py-16">
<p class="text-xs font-medium uppercase tracking-widest text-neutral-400">Step 3 of 4</p>
<div class="mt-2 h-1 w-full overflow-hidden rounded-full bg-neutral-200">
<div class="h-full w-3/4 rounded-full bg-neutral-900"></div>
</div>
<h1 class="mt-8 text-2xl font-semibold text-neutral-900">Bring your team in</h1>
<p class="mt-2 text-sm text-neutral-500">People you invite land straight in this workspace. Roles can change later.</p>
<form id="inviteForm" class="mt-6 flex gap-2">
<input id="inviteEmail" type="text" placeholder="name@company.com"
class="w-full rounded-xl border border-neutral-200 px-3.5 py-2.5 text-sm outline-none focus:border-neutral-900 focus:ring-4 focus:ring-neutral-900/10" />
<button class="shrink-0 rounded-xl bg-neutral-900 px-4 py-2.5 text-sm font-medium text-white transition hover:bg-neutral-800">Add</button>
</form>
<p id="inviteError" class="mt-1.5 hidden text-xs text-red-600">That does not look like an email address.</p>
<p class="mt-1.5 text-xs text-neutral-400">Paste a whole list — commas, semicolons or spaces all work.</p>
<ul id="invites" class="mt-6 divide-y divide-neutral-100 overflow-hidden rounded-2xl border border-neutral-200 empty:hidden"></ul>
<p id="inviteEmpty" class="mt-6 rounded-2xl border border-dashed border-neutral-300 px-6 py-8 text-center text-sm text-neutral-400">
Nobody added yet. A workspace of one is fine too.
</p>
<div class="mt-8 flex items-center justify-between">
<a href="#" class="text-sm text-neutral-500 hover:text-neutral-900">I'll do this later</a>
<button id="inviteContinue" class="rounded-xl bg-neutral-900 px-5 py-2.5 text-sm font-medium text-white transition hover:bg-neutral-800">Continue</button>
</div>
</div>
Build an "invite your team" onboarding step with Tailwind CSS, max-w-xl and centred. Above the heading, a step counter and a slim two-tone progress bar. Under the subline, an add row — an email field and a dark Add button side by side — plus a hidden inline error line and a hint that several addresses can be pasted at once. Below that, an empty list container for the invitees and a dashed empty-state panel saying nobody has been added yet. Each invitee row should render as an avatar circle with initials, the address, a role select (Admin, Member, Viewer), and a ✕ remove button. Finish with a footer row: a muted "I'll do this later" link on the left and a dark Continue button on the right. Then add JavaScript that splits pasted input on commas, semicolons and spaces, validates each address and shows the error for bad ones, ignores duplicates already in the list, derives the initials from the address, appends the row with a working remove button, swaps the empty state out once there is at least one invitee, and rewrites the Continue label to "Send 3 invites" or plain "Continue" depending on the count.