BETTER-AUTH. UI
Components

<OrganizationInvitationEmail />

Email template component that invites a user to join an organization.

Usage

import { OrganizationInvitationEmail } from "@better-auth-ui/react/email"
import { render } from "@react-email/render"

const html = await render(
  // biome-ignore lint/a11y/useValidAriaRole: `role` is a prop on the email component, not an ARIA role.
  <OrganizationInvitationEmail
    url="https://better-auth-ui.com/auth/accept-invitation?invitationId=example"
    email="invitee@example.com"
    inviterName="Jane Doe"
    inviterEmail="jane@example.com"
    organizationName="Acme Inc."
    role="member"
    appName="Better Auth UI"
    logoURL={{
      light: "/favicon-96x96.png",
      dark: "/favicon-96x96-inverted.png"
    }}
    expirationHours={48}
    darkMode={true}
    poweredBy={true}
  />
)

Installation

npx shadcn@latest registry add @better-auth-ui=https://better-auth-ui.com/r/{style}/{name}.json
npx shadcn@latest add @better-auth-ui/organization-invitation-email

Server setup

Wire the email into the Better Auth organization plugin via sendInvitationEmail. Point url at the direct invitation view registered by organizationPlugin().

auth.ts
import { OrganizationInvitationEmail } from "@better-auth-ui/react/email"
import { render } from "@react-email/render"
import { betterAuth } from "better-auth"
import { organization } from "better-auth/plugins"

const baseUrl = process.env.BETTER_AUTH_URL!

export const auth = betterAuth({
  plugins: [
    organization({
      async sendInvitationEmail(data) {
        const html = await render(
          <OrganizationInvitationEmail
            url={`${baseUrl}/auth/accept-invitation?invitationId=${data.id}`}
            email={data.email}
            inviterName={data.inviter.user.name}
            inviterEmail={data.inviter.user.email}
            organizationName={data.organization.name}
            organizationLogoURL={data.organization.logo ?? undefined}
            role={data.role}
            appName="My App"
            poweredBy
          />
        )

        await sendEmail({
          to: data.email,
          subject: `You're invited to ${data.organization.name}`,
          html
        })
      }
    })
  ]
})

Add organizationPlugin().viewPaths.auth.acceptInvitation to your auth route allow-list. Use {baseUrl}/settings/organizations only when you want the invitation email to open the full pending-invitations list instead.

Props

Prop

Type

Features

  • Inviter name and email display
  • Organization name and optional organization logo
  • Role being offered (e.g. member, admin, owner)
  • Accept invitation button linking to the direct invitation view
  • Fallback URL for manual copy/paste
  • Optional expiration time
  • Security notice for unexpected invitations
  • Customizable branding and styling
  • Support for light/dark mode themes
  • Localization support

Last updated on

On this page