@haykal/auth-ui
v1.0.0
Published
Haykal Auth UI — Reusable authentication screens, forms, and flows
Readme
@haykal/auth-ui
Pre-built authentication UI components for React — login, registration, password reset, email verification, and session management screens using a controlled/uncontrolled pattern.
Installation
pnpm add @haykal/auth-uiPeer dependencies: @haykal/auth-client, @haykal/ui, react, react-hook-form, zod
Architecture
The package follows a two-tier pattern with smart screens:
- Forms — Pure presentational form components with
react-hook-form+ Zod validation - Screens — Card-wrapped layouts that work in two modes:
- Uncontrolled (default) — Handles API calls internally via
@haykal/auth-client - Controlled — Parent manages API calls by providing
onSubmit,error, andisLoadingprops
- Uncontrolled (default) — Handles API calls internally via
Forms (presentational, controlled by props)
└── Screens (smart — uncontrolled by default, controllable via props)This follows the same pattern as React's <input> element — works standalone by default, but can be controlled when needed.
Key Exports
Screens (Smart Components)
Every screen component supports both uncontrolled (default, handles API internally) and controlled (parent manages API) modes.
| Export | Description | Uncontrolled Hook |
| ---------------------- | ----------------------------- | ---------------------------------------------------- |
| LoginScreen | Login with email + password | useAuth().login() |
| RegisterScreen | User registration | useAuth().register() |
| ForgotPasswordScreen | Request password reset email | useAuthControllerForgotPassword() |
| ResetPasswordScreen | Reset password with token | useAuthControllerResetPassword() |
| ChangePasswordScreen | Authenticated password change | useAuthControllerChangePassword() |
| VerifyEmailScreen | Email verification with token | useAuthControllerVerifyEmail() |
| SessionsScreen | Active session management | useAuthControllerListSessions() + revoke mutations |
Forms
| Export | Description |
| -------------------- | ---------------------------------------- |
| LoginForm | Email + password form |
| RegisterForm | Registration form with password strength |
| ForgotPasswordForm | Email input for reset request |
| ResetPasswordForm | New password form |
| ChangePasswordForm | Current + new password form |
| VerifyEmailForm | Token verification form |
UI Components
| Export | Description |
| --------------------------- | ----------------------------------------- |
| AuthCardLayout | Centered card wrapper for auth pages |
| AuthErrorAlert | Error display with auth-specific messages |
| OAuthButton | Social login button |
| PasswordStrengthIndicator | Visual password strength meter |
| SessionCard | Session info display with revoke action |
Auth Flow
| Export | Description |
| ------------------- | ------------------------------------------------------ |
| AuthFlow | Route-agnostic state machine for multi-step auth flows |
| AuthFlowStep | Enum of auth steps (login, register, verify, etc.) |
| AuthFlowCallbacks | Callback interface for auth flow transitions |
Hooks
| Export | Description |
| --------------------- | --------------------------------------------- |
| useAuthErrorMessage | Convert error codes to user-friendly messages |
| usePasswordStrength | Calculate password strength score |
Zod Schemas
| Export | Description |
| ---------------------- | ----------------------------- |
| loginSchema | Login form validation |
| registerSchema | Registration validation |
| forgotPasswordSchema | Forgot password validation |
| resetPasswordSchema | Reset password validation |
| changePasswordSchema | Change password validation |
| verifyEmailSchema | Email verification validation |
Usage Examples
Uncontrolled Mode (Default — Quickest Setup)
Screens handle API calls internally. Just provide callbacks for navigation:
// app/(auth)/login/page.tsx
import { LoginScreen } from '@haykal/auth-ui';
export default function LoginPage() {
const router = useRouter();
return (
<LoginScreen
onSuccess={() => router.push('/dashboard')}
onForgotPassword={() => router.push('/forgot-password')}
onRegister={() => router.push('/register')}
/>
);
}Controlled Mode (Custom API Logic)
Pass onSubmit to take full control over API calls:
import { LoginScreen } from '@haykal/auth-ui';
export default function CustomLoginPage() {
const customLogin = useMyCustomLogin();
return (
<LoginScreen
onSubmit={async (values) => {
await customLogin.mutate(values);
await analytics.track('login_success');
router.push('/onboarding');
}}
error={customLogin.error}
isLoading={customLogin.isPending}
/>
);
}Using the Auth Flow State Machine
import { AuthFlow } from '@haykal/auth-ui';
export default function AuthPage() {
return (
<AuthFlow
step="login"
onNavigate={(event) => router.push(`/auth/${event.step}`)}
onLoginSuccess={() => router.push('/dashboard')}
onRegisterSuccess={() => router.push('/verify-email')}
/>
);
}Using Forms Directly
For maximum control, use the form components directly:
import { LoginForm, loginSchema } from '@haykal/auth-ui';
export default function CustomLogin() {
return (
<LoginForm
onSubmit={async (data) => {
// data is validated against loginSchema
await myCustomLogin(data.email, data.password);
}}
isLoading={false}
/>
);
}Controlled vs Uncontrolled — Quick Reference
| Prop provided? | Mode | Behavior |
| -------------- | ------------ | ------------------------------------------------------------------- |
| No onSubmit | Uncontrolled | Screen calls @haykal/auth-client hooks internally |
| Has onSubmit | Controlled | Screen delegates to your handler, uses your error and isLoading |
Both modes support onSuccess and onError callbacks.
Related Packages
@haykal/auth-backend— Backend auth module@haykal/auth-client— React Query hooks (useAuth,useCurrentUser)@haykal/ui— Base UI component library (shadcn/ui)
Further Reading
- Admin App Development — Building pages in the admin dashboard
- Client SDK Generation — Orval pipeline and regeneration
