Login
A production-ready login component with email/password, Azure AD / social SSO, remember-me toggle, error state, and MFA step. Available as a drop-in <PrimusLogin> component (React/Angular) or as a plain HTML recipe using @primus/ui-core.
Components used​
Button · Input · Toggle · Card · Badge
Code​
- HTML · @primus/ui-core
- React
- Angular
<div class="auth-shell">
<div class="card" style="max-width:400px;padding:2.5rem">
<!-- Brand -->
<div style="text-align:center;margin-bottom:1.75rem">
<h2>Sign in to your account</h2>
<p>Enter your credentials to continue</p>
</div>
<!-- Microsoft SSO -->
<button class="outline" style="width:100%">
Continue with Microsoft
</button>
<div class="auth-divider">or sign in with email</div>
<!-- Fields -->
<div class="vstack" style="gap:1rem">
<label data-field>
Email address
<input type="email" placeholder="name@company.com" autocomplete="email" />
</label>
<label data-field>
Password
<input type="password" placeholder="••••••••" autocomplete="current-password" />
</label>
<!-- Error state (show on failed login) -->
<div role="alert" data-variant="danger">
Invalid email or password. Please try again.
</div>
<!-- Remember me -->
<label>
<input type="checkbox" role="switch" />
Keep me signed in for 30 days
</label>
<button style="width:100%">Sign in</button>
</div>
</div>
</div>
import { PrimusLogin } from 'primus-react-ui';
// Option A — Drop-in component (handles all state internally)
export function LoginPage() {
return (
<PrimusLogin
title="Sign in to your account"
showEmailLogin
socialProviders={['azure', 'google']}
onLogin={({ email, password }) => signIn(email, password)}
onSocialLogin={(provider) => signInWithProvider(provider)}
/>
);
}
// Option B — With PrimusProvider (recommended for SPAs)
import { PrimusProvider, PrimusLogin, usePrimusAuth } from 'primus-react-ui';
function App() {
return (
<PrimusProvider
authority="https://api.yourdomain.com"
authBasePath="/api/auth"
clientId="my-app"
>
<LoginPage />
</PrimusProvider>
);
}
function LoginPage() {
const { login } = usePrimusAuth();
return (
<PrimusLogin
showEmailLogin
socialProviders={['azure', 'auth0', 'google']}
onLogin={({ username, password }) =>
login({ email: username, password })
}
/>
);
}
<!-- login.component.html -->
<primus-login
title="Sign in to your account"
subtitle="Enter your credentials to continue"
[showEmailLogin]="true"
[socialProviders]="['azure', 'google']"
authEndpoint="/api/auth"
theme="light"
[useService]="true"
(onLogin)="onLogin($event)"
(onSocialLogin)="onSocialLogin($event)">
</primus-login>
// login.component.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '@primus/auth';
@Component({ templateUrl: './login.component.html' })
export class LoginComponent {
constructor(
private auth: AuthService,
private router: Router,
) {}
async onLogin(payload: { email: string; password: string }) {
await this.auth.signIn(payload.email, payload.password);
this.router.navigate(['/dashboard']);
}
onSocialLogin(provider: string) {
this.auth.signInWithProvider(provider);
}
}
Props​
| Prop | Type | Default | Description |
|---|---|---|---|
title | string | 'Sign in' | Heading text |
subtitle | string | '' | Supporting text below heading |
logo | string | — | URL to logo image |
showEmailLogin | boolean | true | Show email/password form |
socialProviders | ('azure' | 'google' | 'github' | 'auth0')[] | [] | Social SSO buttons to display |
authEndpoint | string | '/api/auth' | Base path for auth API calls |
theme | 'light' | 'dark' | 'auto' | 'auto' | Theme override |
useService | boolean | true | Angular: auto-wire PrimusAuthService |
onLogin / (onLogin) | (payload) => void | — | Emits { email, password } on form submit |
onSocialLogin / (onSocialLogin) | (provider) => void | — | Emits provider name on SSO click |
Variations​
MFA step​
After credentials are verified, show a 6-digit OTP card:
<div class="card" style="max-width:400px;padding:2.5rem;text-align:center">
<h2>Verify your identity</h2>
<p>Enter the code from your authenticator app.</p>
<input type="text" inputmode="numeric" maxlength="6"
placeholder="000 000"
style="text-align:center;font-size:1.5rem;letter-spacing:0.3em;width:100%" />
<button style="width:100%;margin-top:1rem">Verify</button>
<a href="#" style="display:block;margin-top:0.75rem;font-size:0.8rem">
Use a backup code instead
</a>
</div>
Error state​
Set aria-invalid="true" on the password field and show <div role="alert" data-variant="danger">:
<div role="alert" data-variant="danger">
Invalid email or password. Please try again.
</div>
Loading state​
The Sign in button automatically shows a spinner when loading={true} (React)
or [loading]="true" (Angular). No manual handling needed.
The Login Page cookbook recipe shows a full-page implementation with layout shell, remember-me toggle, and MFA step wired together.
See the Changelog for version history and breaking changes.