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/uiComponents 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
| Component | Description |
|---|---|
SignIn | Email/password and magic-link sign-in form |
SignUp | New account registration form |
UserButton | Avatar dropdown with sign-out and custom menu items |
ForgotPassword | Password reset request form |
TwoFactorVerify | TOTP/backup-code entry for 2FA flows |
OAuthButtons | Social login buttons (Google, GitHub, Discord, and more) |
AuthCard | Generic 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>
);
}