Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Customizing CSS

This page explains how to create your own CSS theme for the built-in UI pages. If you just want to pick a ready-made theme, see Built-in Themes first.

The built-in pages use CSS Custom Properties (CSS variables) for theming. You can override these variables to change colors, fonts, spacing, and more without modifying the HTML structure.

Quick Start

  1. Create a CSS file with your overrides:
/* static/my-theme.css */
:root {
    --o2p-primary: #ff6b6b;
    --o2p-background: #1a1a2e;
}
  1. Serve the CSS file from your application (see Serving Your CSS File).

  2. Set the environment variable:

# .env
O2P_CUSTOM_CSS_URL=/static/my-theme.css

CSS Custom Properties Reference

Colors

PropertyDefaultDescription
--o2p-primary#4f46e5Primary action buttons
--o2p-primary-hover#4338caPrimary button hover state
--o2p-oauth2#6366f1OAuth2 buttons
--o2p-oauth2-hover#4f46e5OAuth2 button hover state
--o2p-passkey#818cf8Passkey buttons
--o2p-passkey-hover#6366f1Passkey button hover state
--o2p-danger#dc2626Delete/danger buttons
--o2p-danger-hover#b91c1cDanger button hover state
--o2p-secondary#6b7280Secondary/cancel buttons
--o2p-secondary-hover#4b5563Secondary button hover state

Text

PropertyDefaultDescription
--o2p-text#111827Primary text color
--o2p-text-secondary#4b5563Secondary text color
--o2p-text-light#9ca3afLight/muted text

Backgrounds

PropertyDefaultDescription
--o2p-background#f9fafbPage background
--o2p-surface#ffffffCard/container background
--o2p-surface-alt#f3f4f6Alternate surface (items)

Borders & Radius

PropertyDefaultDescription
--o2p-border#e5e7ebBorder color
--o2p-border-light#f3f4f6Light border color
--o2p-radius-sm4pxSmall radius (inputs)
--o2p-radius-md6pxMedium radius (buttons)
--o2p-radius-lg8pxLarge radius (cards)

Spacing

PropertyDefaultDescription
--o2p-space-xs4pxExtra small spacing
--o2p-space-sm8pxSmall spacing
--o2p-space-md16pxMedium spacing
--o2p-space-lg24pxLarge spacing
--o2p-space-xl32pxExtra large spacing

Typography

PropertyDefaultDescription
--o2p-fontsystem-ui, -apple-system, ...Font family
--o2p-font-size16pxBase font size
--o2p-line-height1.6Line height

Shadows

PropertyDefaultDescription
--o2p-shadow0 1px 3px rgba(0,0,0,0.08)Standard shadow
--o2p-shadow-lg0 4px 12px rgba(0,0,0,0.1)Large shadow

Serving Your CSS File

Add a route in your application to serve the custom CSS:

use axum::{Router, routing::get, response::Response, http::{StatusCode, header::CONTENT_TYPE}};

async fn serve_custom_css() -> Response {
    let css = include_str!("../static/my-theme.css");
    Response::builder()
        .status(StatusCode::OK)
        .header(CONTENT_TYPE, "text/css")
        .body(css.into())
        .unwrap()
}

let app = Router::new()
    .route("/static/my-theme.css", get(serve_custom_css))
    .merge(oauth2_passkey_full_router());

Credential Type Styling

Passkey and OAuth2 credentials are visually distinguished with colored left borders:

  • Passkey credentials: Uses --o2p-passkey color
  • OAuth2 accounts: Uses --o2p-secondary color

These use CSS classes .passkey and .oauth2 on credential items:

.item.passkey {
    border-left-color: var(--o2p-passkey);
}

.item.oauth2 {
    border-left-color: var(--o2p-secondary);
}

Examples

Dark Mode

/* dark-theme.css */
:root {
    /* Dark backgrounds */
    --o2p-background: #1a1a2e;
    --o2p-surface: #16213e;
    --o2p-surface-alt: #1f2b47;

    /* Light text */
    --o2p-text: #e4e4e4;
    --o2p-text-secondary: #a0a0a0;
    --o2p-text-light: #6c6c6c;

    /* Darker borders */
    --o2p-border: #0f3460;
    --o2p-border-light: #1a3a5c;

    /* Adjusted shadows for dark mode */
    --o2p-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
    --o2p-shadow-lg: 0 4px 16px rgba(0, 0, 0, 0.4);
}

Brand Colors

/* brand-theme.css */
:root {
    /* Use your brand's primary color */
    --o2p-primary: #e91e63;
    --o2p-primary-hover: #c2185b;
}

/* Override the login page gradient */
.login-page {
    background: linear-gradient(135deg, #e91e63 0%, #9c27b0 100%);
}

Rounded Style

/* rounded-theme.css */
:root {
    --o2p-radius-sm: 12px;
    --o2p-radius-md: 16px;
    --o2p-radius-lg: 24px;
}

When to Use Templates

CSS customization is sufficient for most branding needs. Consider template customization when you need:

  • Different page structure or layout
  • Additional form fields or sections
  • Integration with your existing design system
  • Completely different user flow