@bettercone/ui
Components

Organization Components

Multi-tenant organization and team management components

Organization Components

4 production-ready components for building B2B SaaS with multi-tenancy.

Components

OrganizationSwitcher

Dropdown to switch between user's organizations (like Vercel/Linear).

import { OrganizationSwitcher } from '@bettercone/ui';
<OrganizationSwitcher authClient={authClient} />

Features: Search organizations, create new org, personal account toggle

Included Sub-components

  • CreateOrganizationDialog - Modal to create new organization with name, slug, and logo upload

OrganizationSettingsCards

Complete organization settings dashboard.

import { OrganizationSettingsCards } from '@bettercone/ui';
<OrganizationSettingsCards authClient={authClient} />

Features: Organization name, slug, logo, and deletion settings

Included Sub-components

  • OrganizationNameCard - Edit organization name
  • OrganizationSlugCard - Edit URL-safe slug
  • OrganizationLogoCard - Upload/update logo with crop/resize
  • DeleteOrganizationCard - Delete organization (owner only, requires confirmation)

OrganizationMembersCard

List and manage organization members with roles.

import { OrganizationMembersCard } from '@bettercone/ui';
<OrganizationMembersCard authClient={authClient} />

Features: View members, update roles, remove members, invite new

Included Sub-components

  • InviteMemberDialog - Send email invitations with role selection
  • UpdateMemberRoleDialog - Change member's role (owner, admin, member)
  • RemoveMemberDialog - Remove member with confirmation
  • LeaveOrganizationDialog - Leave organization (if not owner)

OrganizationInvitationsCard

Manage pending invitations.

import { OrganizationInvitationsCard } from '@bettercone/ui';
<OrganizationInvitationsCard authClient={authClient} />

Features: View pending invites, resend, cancel

  • AcceptInvitationCard - Accept or decline organization invitation (for invitation pages)
  • UserInvitationsCard - User's list of pending invitations from all organizations (for user dashboard)

Quick Start

Complete Organization Dashboard

import {
  OrganizationSwitcher,
  OrganizationSettingsCards,
  OrganizationMembersCard,
  OrganizationInvitationsCard
} from '@bettercone/ui';
import { authClient } from '@/lib/auth-client';

export default function OrganizationPage() {
  return (
    <div className="space-y-6">
      <OrganizationSwitcher authClient={authClient} />
      
      <div className="grid gap-6">
        <OrganizationSettingsCards authClient={authClient} />
        <OrganizationMembersCard authClient={authClient} />
        <OrganizationInvitationsCard authClient={authClient} />
      </div>
    </div>
  );
}

Organization Switcher in Header

<header className="border-b">
  <div className="container flex items-center justify-between py-4">
    <Logo />
    <OrganizationSwitcher authClient={authClient} />
    <UserButton authClient={authClient} />
  </div>
</header>

Team Page Layout

import { OrganizationMembersCard } from '@bettercone/ui';
import { authClient } from '@/lib/auth-client';

export default function TeamPage() {
  return (
    <div className="space-y-8">
      <div className="flex justify-between items-center">
        <h1>Team</h1>
      </div>
      
      <OrganizationMembersCard authClient={authClient} />
    </div>
  );
}

Invitation Acceptance Page

import { AcceptInvitationCard } from '@bettercone/ui';
import { authClient } from '@/lib/auth-client';

export default function AcceptInvitePage({ params }: { params: { id: string } }) {
  return (
    <div className="max-w-md mx-auto mt-16">
      <AcceptInvitationCard 
        authClient={authClient} 
        invitationId={params.id}
      />
    </div>
  );
}

Advanced Usage

Settings Page with Sections

import { 
  OrganizationSettingsCards,
  OrganizationMembersCard
} from '@bettercone/ui';

<div className="max-w-4xl mx-auto space-y-8">
  <section>
    <h2>General</h2>
    <OrganizationSettingsCards authClient={authClient} />
  </section>
  
  <section>
    <h2>Members</h2>
    <OrganizationMembersCard authClient={authClient} />
  </section>
</div>

Individual Settings Components

If you need more control, you can import individual components:

import {
  OrganizationNameCard,
  OrganizationSlugCard,
  OrganizationLogoCard,
  DeleteOrganizationCard
} from '@bettercone/ui';

// Use them separately
<OrganizationNameCard authClient={authClient} />
<OrganizationSlugCard authClient={authClient} />
<OrganizationLogoCard authClient={authClient} />
<DeleteOrganizationCard authClient={authClient} />

Permission System

All components automatically respect Better Auth's role-based permissions:

  • Owner: Full access (can delete org, manage all settings)
  • Admin: Manage members, settings (cannot delete org)
  • Member: Read-only access

Features

OrganizationSwitcher

  • ✅ Search organizations
  • ✅ Create new organization
  • ✅ Personal account toggle
  • ✅ Organization avatars
  • ✅ Keyboard navigation

OrganizationSettingsCards

  • ✅ Edit organization name
  • ✅ Edit URL-safe slug
  • ✅ Upload/update logo
  • ✅ Delete organization
  • ✅ Owner-only controls

OrganizationMembersCard

  • ✅ View all members
  • ✅ Role badges (owner, admin, member)
  • ✅ Invite new members
  • ✅ Update member roles
  • ✅ Remove members
  • ✅ Leave organization

OrganizationInvitationsCard

  • ✅ View pending invitations
  • ✅ Resend invitations
  • ✅ Cancel invitations
  • ✅ Expiration status

Props Reference

Common Props

PropTypeDescription
authClientAnyAuthClientBetter Auth client (required)
organizationIdstringSpecific org ID (optional, auto-detected)
onSuccess() => voidSuccess callback
onError(error) => voidError callback
classNamestringCSS classes

OrganizationSwitcher

PropTypeDescription
authClientAnyAuthClientBetter Auth client (required)
onOrganizationChange(org) => voidCallback when switching
classNamestringCSS classes

AcceptInvitationCard

PropTypeDescription
authClientAnyAuthClientBetter Auth client (required)
invitationIdstringInvitation ID (required)
onAccept() => voidCallback after accepting
onDecline() => voidCallback after declining