kavachOS

UI components

Pre-built sign-in, sign-up, and user management components.

@kavachos/ui provides drop-in React components for auth flows. Each component renders inside KavachProvider from @kavachos/react and wires up to your KavachOS API route automatically — no manual fetch calls required.

Components require @kavachos/react to be installed and a KavachProvider wrapping your app. See the React hooks page for provider setup.

Installation

pnpm add @kavachos/ui

Components are unstyled by default and rely on Tailwind CSS for layout and spacing. Add @kavachos/ui to your tailwind.config.ts content paths:

// tailwind.config.ts
export default {
  content: [
    './src/**/*.{ts,tsx}',
    './node_modules/@kavachos/ui/src/**/*.{ts,tsx}',
  ],
};

Available components

ComponentDescription
SignInEmail/password and magic-link sign-in form
SignUpNew account registration form
UserButtonAvatar dropdown with sign-out and custom menu items
ForgotPasswordPassword reset request form
TwoFactorVerifyTOTP/backup-code entry for 2FA flows
OAuthButtonsSocial login buttons (Google, GitHub, Discord, and more)
AuthCardGeneric card shell for building custom auth pages

SignIn

Renders an email/password form. Pass showMagicLink to add a passwordless tab. Pass providers to show OAuth buttons above the form.

import { SignIn } from '@kavachos/ui';
import { OAUTH_PROVIDERS } from '@kavachos/ui';

export default function LoginPage() {
  return (
    <SignIn
      providers={[OAUTH_PROVIDERS.google, OAUTH_PROVIDERS.github]}
      showMagicLink
      signUpUrl="/sign-up"
      forgotPasswordUrl="/forgot-password"
      onSuccess={() => window.location.href = '/dashboard'}
    />
  );
}

Prop

Type

SignUp

import { SignUp } from '@kavachos/ui';

export default function RegisterPage() {
  return (
    <SignUp
      showName
      confirmPassword
      signInUrl="/sign-in"
      onSuccess={() => window.location.href = '/dashboard'}
    />
  );
}

Prop

Type

UserButton

Renders an avatar that opens a dropdown menu. Includes sign-out by default. Pass menuItems to add custom actions.

import { UserButton } from '@kavachos/ui';

export default function Nav() {
  return (
    <UserButton
      showEmail
      menuItems={[
        { label: 'Settings', onClick: () => router.push('/settings') },
        { label: 'Delete account', onClick: handleDelete, danger: true },
      ]}
      onSignOut={() => router.push('/sign-in')}
    />
  );
}

OAuthButtons

Use standalone when you want social login without the full sign-in card.

import { OAuthButtons, OAUTH_PROVIDERS } from '@kavachos/ui';

<OAuthButtons
  providers={[
    OAUTH_PROVIDERS.google,
    OAUTH_PROVIDERS.github,
    OAUTH_PROVIDERS.discord,
  ]}
  mode="signin"
  layout="list"
/>

OAUTH_PROVIDERS ships with metadata and icons for Google, GitHub, GitLab, Discord, Twitter, Facebook, Microsoft, Apple, LinkedIn, Slack, Notion, Reddit, Spotify, and Twitch. You can also pass a custom provider object matching OAuthProviderMeta.

Customization

Class name overrides

Every component accepts a classNames prop with keys for each sub-element. Pass a string to append classes, or a function that receives the default class string.

<SignIn
  classNames={{
    card: 'shadow-none border-0',
    button: (defaults) => `${defaults} bg-violet-600 hover:bg-violet-500`,
    input: 'rounded-none border-b border-zinc-300',
  }}
/>

Slot replacement

Pass a components prop to replace any primitive (input, button, link, divider, error). Useful when you need to use your own design system components.

import { SignIn } from '@kavachos/ui';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';

<SignIn
  components={{
    Button: ({ children, loading, ...props }) => (
      <Button {...props} disabled={loading}>{children}</Button>
    ),
    Input: ({ label, error, ...props }) => (
      <div>
        <label>{label}</label>
        <Input {...props} />
        {error && <p className="text-red-500 text-xs">{error}</p>}
      </div>
    ),
  }}
/>

The cx utility is exported from @kavachos/ui for merging class names in your own slot components.

Framework examples

Next.js App Router

// app/(auth)/sign-in/page.tsx
import { SignIn } from '@kavachos/ui';

export default function SignInPage() {
  return (
    <main className="flex min-h-screen items-center justify-center">
      <SignIn
        signUpUrl="/sign-up"
        forgotPasswordUrl="/forgot-password"
        onSuccess={() => {
          // Client navigation — wrap in 'use client' if needed
          window.location.href = '/dashboard';
        }}
      />
    </main>
  );
}

Vite + React Router

// src/pages/sign-in.tsx
import { useNavigate } from 'react-router-dom';
import { SignIn } from '@kavachos/ui';

export function SignInPage() {
  const navigate = useNavigate();

  return (
    <div className="flex min-h-screen items-center justify-center">
      <SignIn
        signUpUrl="/sign-up"
        onSuccess={() => navigate('/dashboard')}
      />
    </div>
  );
}

Next steps

On this page