# @neondatabase/auth-ui
> React UI components and theming for Neon Auth - pre-built sign-in, sign-up, and user management forms with customizable styling.
## Installation
```bash
npm install @neondatabase/auth-ui @neondatabase/auth
```
## CSS Import Decision
| Your Setup | Import Path | Bundle Size |
|------------|-------------|-------------|
| No Tailwind | `@import '@neondatabase/auth-ui/css'` | ~47KB |
| Tailwind v4 | `@import '@neondatabase/auth-ui/tailwind'` | ~2KB (tokens only) |
**Rule:** Never import both. Causes duplicate styles.
**Without Tailwind (pre-built CSS):**
```typescript
// In layout.tsx or _app.tsx
import "@neondatabase/auth-ui/css";
```
**With Tailwind v4:**
```css
/* globals.css */
@import 'tailwindcss';
@import '@neondatabase/auth-ui/tailwind';
/* Your overrides go here */
```
## Available Components
### Authentication Forms
- `SignInForm` - Email/password + OAuth sign in
- `SignUpForm` - New user registration
- `AuthView` - Dynamic view based on route path
- `SignedIn` / `SignedOut` / `AuthLoading` - Conditional rendering wrappers
### Account Management
- `UserButton` - Avatar with dropdown menu (sign out, settings)
- `UserAvatar` - Just the avatar image
- `AccountView` - Account settings pages
- `SettingsCard` - Individual settings sections
### Organization (if enabled on server)
- `OrganizationView` - Org management pages
- `OrganizationSwitcher` - Switch between organizations
## Provider Props
```typescript
import { NeonAuthUIProvider } from "@neondatabase/auth-ui";
{children}
```
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `authClient` | `NeonAuthPublicApi` | Required | Your auth client from `createAuthClient()` |
| `className` | `string` | - | Additional CSS classes for the wrapper div |
| `defaultTheme` | `'light' \| 'dark' \| 'system'` | `'system'` | Initial theme for next-themes |
| `redirectTo` | `string` | - | URL to redirect after successful auth |
## CSS Layer Architecture
Auth-UI styles use `@layer neon-auth` for cascade priority control. This ensures **your CSS always wins**.
```
Priority (lowest to highest):
1. @layer neon-auth ← Auth-UI styles live here
2. @layer base ← Your base styles
3. @layer components ← Your component styles
4. @layer utilities ← Tailwind utilities
5. Unlayered CSS ← Your custom overrides (HIGHEST priority)
```
**What this means:**
- Your `:root` variables always override auth-ui defaults
- Your unlayered CSS always beats auth-ui styles
- No need to use `!important` or specificity hacks
**Example:**
```css
/* This ALWAYS wins over auth-ui's default --primary */
:root {
--primary: oklch(0.55 0.25 250);
}
```
## Theme Tokens
Auth-UI CSS is designed to **never override your theme**. It uses a fallback pattern that respects your existing CSS variables.
### How It Works
Auth-UI defines `--neon-*` prefixed variables on `:root` inside `@layer neon-auth`:
```css
--neon-primary: var(--primary, oklch(0.205 0 0));
```
This means:
1. If you define `--primary` in `:root`, auth-ui uses YOUR value
2. If you don't, auth-ui uses its default
### Customizing Colors
Override in `:root` (light) and `.dark` (dark mode):
```css
:root {
/* Primary - buttons, links, focus rings */
--primary: oklch(0.205 0 0);
--primary-foreground: oklch(0.985 0 0);
/* Secondary - secondary buttons */
--secondary: oklch(0.97 0 0);
--secondary-foreground: oklch(0.205 0 0);
/* Background/Foreground - page colors */
--background: oklch(1 0 0);
--foreground: oklch(0.145 0 0);
/* Muted - placeholders, disabled states */
--muted: oklch(0.97 0 0);
--muted-foreground: oklch(0.556 0 0);
/* Accent - hover states */
--accent: oklch(0.97 0 0);
--accent-foreground: oklch(0.205 0 0);
/* Destructive - errors, delete actions */
--destructive: oklch(0.577 0.245 27.325);
/* UI Elements */
--border: oklch(0.922 0 0);
--input: oklch(0.922 0 0);
--ring: oklch(0.708 0 0);
--radius: 0.625rem;
}
.dark {
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--ring: oklch(0.556 0 0);
}
```
### Token Pairing Rules
**CRITICAL:** Always override pairs together to maintain contrast.
| Background Token | Foreground Token | Min Contrast |
|-----------------|------------------|--------------|
| `--primary` | `--primary-foreground` | 4.5:1 |
| `--secondary` | `--secondary-foreground` | 4.5:1 |
| `--background` | `--foreground` | 4.5:1 |
| `--muted` | `--muted-foreground` | 4.5:1 |
| `--accent` | `--accent-foreground` | 4.5:1 |
| `--destructive` | `--destructive-foreground` | 4.5:1 |
### Additional Tokens
```css
:root {
/* Cards and Popovers */
--card: oklch(1 0 0);
--card-foreground: oklch(0.145 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.145 0 0);
/* Border Radius Scale */
--radius: 0.625rem; /* Base (10px) */
--radius-sm: calc(var(--radius) - 4px);
--radius-md: calc(var(--radius) - 2px);
--radius-lg: var(--radius);
--radius-xl: calc(var(--radius) + 4px);
/* Sidebar (if using sidebar components) */
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar-primary: oklch(0.205 0 0);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
/* Charts (if using data visualization) */
--chart-1: oklch(0.646 0.222 41.116);
--chart-2: oklch(0.6 0.118 184.704);
--chart-3: oklch(0.398 0.07 227.392);
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
}
```
## OKLCH Color Format
Neon Auth UI uses OKLCH for perceptually uniform colors.
**Format:** `oklch(L C H)` or `oklch(L C H / alpha)`
| Parameter | Range | Description |
|-----------|-------|-------------|
| L (Lightness) | 0-1 | 0 = black, 1 = white |
| C (Chroma) | 0-0.4 | 0 = gray, higher = more vivid |
| H (Hue) | 0-360 | Color wheel degrees |
| alpha | 0-1 or 0%-100% | Opacity |
**Examples:**
```css
--primary: oklch(0.55 0.25 250); /* Vivid blue */
--primary: oklch(0.55 0.25 250 / 50%); /* 50% opacity */
--muted: oklch(0.5 0 0); /* Neutral gray (no chroma) */
```
**Convert HEX/RGB to OKLCH:** https://oklch.com
## Dark Mode Implementation
### Option 1: next-themes (Recommended for Next.js)
```bash
npm install next-themes
```
```typescript
// app/layout.tsx
import { ThemeProvider } from "next-themes";
export default function Layout({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
```typescript
// components/theme-toggle.tsx
"use client";
import { useTheme } from "next-themes";
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
return (
);
}
```
### Option 2: Vanilla JavaScript
```typescript
// Check system preference
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
// Apply dark mode
document.documentElement.classList.toggle("dark", prefersDark);
// Toggle manually
function toggleDarkMode() {
document.documentElement.classList.toggle("dark");
}
```
### Option 3: CSS Only (System Preference)
```css
@media (prefers-color-scheme: dark) {
:root {
/* Dark mode values applied automatically */
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
/* ... other dark tokens */
}
}
```
## Common Mistakes
### 1. Importing Both CSS Paths
```css
/* WRONG - duplicate styles, ~94KB */
@import '@neondatabase/auth-ui/css';
@import '@neondatabase/auth-ui/tailwind';
/* CORRECT - pick one */
@import '@neondatabase/auth-ui/css';
```
### 2. Missing Foreground Pairs
```css
/* WRONG - white text on light background */
:root {
--primary: oklch(0.9 0.1 250);
}
/* CORRECT - ensure contrast */
:root {
--primary: oklch(0.9 0.1 250);
--primary-foreground: oklch(0.1 0 0);
}
```
### 3. Using HEX/RGB Instead of OKLCH
```css
/* WRONG - may not work correctly */
:root {
--primary: #3b82f6;
}
/* CORRECT - use OKLCH format */
:root {
--primary: oklch(0.59 0.2 262);
}
```
### 4. Wrong CSS Import Order
```css
/* WRONG - overrides load before Neon CSS */
@import './my-overrides.css';
@import '@neondatabase/auth-ui/css';
/* CORRECT - Neon CSS first, then overrides */
@import '@neondatabase/auth-ui/css';
@import './my-overrides.css';
/* OR inline after import */
@import '@neondatabase/auth-ui/css';
:root {
--primary: oklch(0.55 0.25 250);
}
```
### 5. Forgetting Dark Mode Tokens
```css
/* WRONG - light mode only */
:root {
--primary: oklch(0.55 0.25 250);
--primary-foreground: oklch(0.98 0 0);
}
/* CORRECT - both modes */
:root {
--primary: oklch(0.55 0.25 250);
--primary-foreground: oklch(0.98 0 0);
}
.dark {
--primary: oklch(0.75 0.2 250);
--primary-foreground: oklch(0.1 0 0);
}
```
## Form Customization
### Props
```typescript
```
### Disabling Features
```typescript
```
### Custom Fields
```typescript
```
## Component-Specific Styling
All UI components accept `classNames` props for targeted customization:
```typescript
import { SignInForm } from "@neondatabase/auth-ui";
```
**Available classNames interfaces:**
- `AuthViewClassNames`
- `AuthFormClassNames`
- `UserAvatarClassNames`
- `UserButtonClassNames`
- `SettingsCardClassNames`
## Browser Support
Auth-UI uses modern CSS features with excellent browser support:
| Feature | Chrome | Firefox | Safari | Edge | Coverage |
|---------|--------|---------|--------|------|----------|
| CSS `@layer` | 99+ | 97+ | 15.4+ | 99+ | ~95% |
| `display: contents` | 65+ | 59+ | 11.1+ | 79+ | ~97% |
| OKLCH colors | 111+ | 113+ | 15.4+ | 111+ | ~95% |
| CSS custom properties | 49+ | 31+ | 9.1+ | 16+ | ~98% |
**Graceful degradation:**
- Older browsers ignore `@layer` but styles still work correctly via `:root` variables
- If OKLCH is unsupported, consider providing HSL fallbacks in your overrides
**Known issues:**
- Safari < 16 may have accessibility issues with `display: contents` (rare edge case)
## Links
- [Full theme.css source](https://github.com/neondatabase/neon-js/blob/main/packages/auth-ui/src/theme.css)
- [OKLCH Color Converter](https://oklch.com)
- [shadcn/ui Theming Guide](https://ui.shadcn.com/docs/theming)
- [better-auth-ui Documentation](https://better-auth-ui.com)
- [next-themes](https://github.com/pacocoursey/next-themes)