themes

Theme management for daisyUI

Built-in Themes

daisyUI provides 35 built-in themes:


source

DaisyUITheme

 DaisyUITheme (value, names=None, module=None, qualname=None, type=None,
               start=1, boundary=None)

All built-in daisyUI themes.

# List all available themes
print(f"Total themes: {len(DaisyUITheme)}")
print("Themes:", [theme.value for theme in DaisyUITheme])
Total themes: 35
Themes: ['light', 'dark', 'cupcake', 'bumblebee', 'emerald', 'corporate', 'synthwave', 'retro', 'cyberpunk', 'valentine', 'halloween', 'garden', 'forest', 'aqua', 'lofi', 'pastel', 'fantasy', 'wireframe', 'black', 'luxury', 'dracula', 'cmyk', 'autumn', 'business', 'acid', 'lemonade', 'night', 'coffee', 'winter', 'dim', 'nord', 'sunset', 'caramellatte', 'abyss', 'silk']
# Theme access
print(f"Light theme: {DaisyUITheme.LIGHT.value}")
print(f"Dark theme: {DaisyUITheme.DARK.value}")
print(f"Cupcake theme: {DaisyUITheme.CUPCAKE.value}")
Light theme: light
Dark theme: dark
Cupcake theme: cupcake

Theme Selection

Helper functions for working with themes:


source

get_theme_value

 get_theme_value (theme:Union[__main__.DaisyUITheme,str],
                  allow_custom:bool=False)

Get the string value of a theme, supporting both enum and string inputs. This allows flexibility in how themes are specified while maintaining type safety.

Type Default Details
theme Union The theme to validate (DaisyUITheme enum or string)
allow_custom bool False If True, allows any string value for custom themes
Returns str The validated theme name as a string
# Test theme value getter
print(get_theme_value(DaisyUITheme.LIGHT))
print(get_theme_value("dark"))

# Test invalid theme
try:
    get_theme_value("invalid-theme")
except ValueError as e:
    print(f"Error: {e}")
light
dark
Error: 'invalid-theme' is not a valid daisyUI theme. Valid themes are: abyss, acid, aqua, autumn, black, bumblebee, business, caramellatte, cmyk, coffee, corporate, cupcake, cyberpunk, dark, dim, dracula, emerald, fantasy, forest, garden, halloween, lemonade, light, lofi, luxury, night, nord, pastel, retro, silk, sunset, synthwave, valentine, winter, wireframe
# Test with custom theme names (allow_custom=True)
print("Testing custom theme names:")
print(f"Custom theme 'my-custom-theme': {get_theme_value('my-custom-theme', allow_custom=True)}")
print(f"Custom theme 'neon_nights': {get_theme_value('neon_nights', allow_custom=True)}")

# Verify that custom themes are rejected when allow_custom=False
try:
    get_theme_value("my-custom-theme", allow_custom=False)
except ValueError as e:
    print(f"\nCustom theme rejected (expected): {e}")
Testing custom theme names:
Custom theme 'my-custom-theme': my-custom-theme
Custom theme 'neon_nights': neon_nights

Custom theme rejected (expected): 'my-custom-theme' is not a valid daisyUI theme. Valid themes are: abyss, acid, aqua, autumn, black, bumblebee, business, caramellatte, cmyk, coffee, corporate, cupcake, cyberpunk, dark, dim, dracula, emerald, fantasy, forest, garden, halloween, lemonade, light, lofi, luxury, night, nord, pastel, retro, silk, sunset, synthwave, valentine, winter, wireframe

Custom Theme Creation

For creating custom themes with full Python abstraction:


source

ThemeColors

Color definitions for a daisyUI theme using OKLCH color space.


source

ThemeConfig

Complete configuration for a custom daisyUI theme.


source

create_theme_css

 create_theme_css (theme:__main__.ThemeConfig)

*Generate CSS for a custom daisyUI theme.

This creates the CSS variables needed for a custom theme when using the CDN approach.*

Type Details
theme ThemeConfig Theme configuration with colors, sizes, and effects
Returns str CSS string with theme variables

Example custom theme:

# Create a custom theme configuration
custom_light_theme: ThemeConfig = {
    "name": "custom_light_theme",
    "default": False,
    "prefersdark": False,
    "color_scheme": "light",
    "colors": {
        "base_100": "oklch(98% 0.005 220)",
        "base_200": "oklch(96% 0.008 215)",
        "base_300": "oklch(92% 0.012 210)",
        "base_content": "oklch(18% 0.015 230)",
        "primary": "oklch(55% 0.18 260)",
        "primary_content": "oklch(98% 0.005 260)",
        "secondary": "oklch(45% 0.12 340)",
        "secondary_content": "oklch(98% 0.005 340)",
        "accent": "oklch(65% 0.15 180)",
        "accent_content": "oklch(15% 0.01 180)",
        "neutral": "oklch(25% 0.01 240)",
        "neutral_content": "oklch(95% 0.005 240)",
        "info": "oklch(60% 0.16 230)",
        "info_content": "oklch(98% 0.005 230)",
        "success": "oklch(58% 0.14 150)",
        "success_content": "oklch(98% 0.005 150)",
        "warning": "oklch(72% 0.16 85)",
        "warning_content": "oklch(18% 0.01 85)",
        "error": "oklch(55% 0.20 15)",
        "error_content": "oklch(98% 0.005 15)"
    },
    "radius_selector": "0.5rem",
    "radius_field": "0.75rem",
    "radius_box": "1.25rem",
    "size_selector": "0.375rem",
    "size_field": "0.375rem",
    "border": "1.5px",
    "depth": 2,
    "noise": 1
}

# Generate the CSS
css = create_theme_css(custom_light_theme)
print(css)
:root:has(input.theme-controller[value=custom_light_theme]:checked),[data-theme="custom_light_theme"] {
  color-scheme: light;
  --color-base-100: oklch(98% 0.005 220);
  --color-base-200: oklch(96% 0.008 215);
  --color-base-300: oklch(92% 0.012 210);
  --color-base-content: oklch(18% 0.015 230);
  --color-primary: oklch(55% 0.18 260);
  --color-primary-content: oklch(98% 0.005 260);
  --color-secondary: oklch(45% 0.12 340);
  --color-secondary-content: oklch(98% 0.005 340);
  --color-accent: oklch(65% 0.15 180);
  --color-accent-content: oklch(15% 0.01 180);
  --color-neutral: oklch(25% 0.01 240);
  --color-neutral-content: oklch(95% 0.005 240);
  --color-info: oklch(60% 0.16 230);
  --color-info-content: oklch(98% 0.005 230);
  --color-success: oklch(58% 0.14 150);
  --color-success-content: oklch(98% 0.005 150);
  --color-warning: oklch(72% 0.16 85);
  --color-warning-content: oklch(18% 0.01 85);
  --color-error: oklch(55% 0.20 15);
  --color-error-content: oklch(98% 0.005 15);
  --radius-selector: 0.5rem;
  --radius-field: 0.75rem;
  --radius-box: 1.25rem;
  --size-selector: 0.375rem;
  --size-field: 0.375rem;
  --border: 1.5px;
  --depth: 2;
  --noise: 1;
}

Theme File Management

Functions for saving and loading theme configurations:


source

save_theme_css

 save_theme_css (theme:__main__.ThemeConfig, path:Union[str,pathlib.Path])

Save a theme configuration as a CSS file.

Type Details
theme ThemeConfig Theme configuration to convert to CSS
path Union File path where CSS will be saved
Returns None None

source

save_theme_json

 save_theme_json (theme:__main__.ThemeConfig,
                  path:Union[str,pathlib.Path])

Save a theme configuration as a JSON file for reuse.

Type Details
theme ThemeConfig Theme configuration to save
path Union File path where JSON will be saved
Returns None None

source

load_theme_json

 load_theme_json (path:Union[str,pathlib.Path])

Load a theme configuration from a JSON file.

Type Details
path Union Path to JSON file containing theme configuration
Returns ThemeConfig Theme configuration dictionary

source

load_style_css

 load_style_css (path:Union[str,pathlib.Path])

Load a theme configuration from a CSS file to a FasthHTML Style element.

Type Details
path Union Path to CSS file containing theme configuration
Returns functools.partial(<function ft at 0x7f16ddbdaca0>, ‘style’, void_=False) FasthHTML Style element
from nbdev.config import get_config
cfg = get_config()
project_dir = cfg.config_path
css_dir = project_dir/"css"
css_dir.mkdir(exist_ok=True, parents=True)
save_path = css_dir/f"{custom_light_theme['name']}.css"
save_theme_css(custom_light_theme, save_path)
load_style_css(save_path)
<style>:root:has(input.theme-controller[value=custom_light_theme]:checked),[data-theme=&quot;custom_light_theme&quot;] {
  color-scheme: light;
  --color-base-100: oklch(98% 0.005 220);
  --color-base-200: oklch(96% 0.008 215);
  --color-base-300: oklch(92% 0.012 210);
  --color-base-content: oklch(18% 0.015 230);
  --color-primary: oklch(55% 0.18 260);
  --color-primary-content: oklch(98% 0.005 260);
  --color-secondary: oklch(45% 0.12 340);
  --color-secondary-content: oklch(98% 0.005 340);
  --color-accent: oklch(65% 0.15 180);
  --color-accent-content: oklch(15% 0.01 180);
  --color-neutral: oklch(25% 0.01 240);
  --color-neutral-content: oklch(95% 0.005 240);
  --color-info: oklch(60% 0.16 230);
  --color-info-content: oklch(98% 0.005 230);
  --color-success: oklch(58% 0.14 150);
  --color-success-content: oklch(98% 0.005 150);
  --color-warning: oklch(72% 0.16 85);
  --color-warning-content: oklch(18% 0.01 85);
  --color-error: oklch(55% 0.20 15);
  --color-error-content: oklch(98% 0.005 15);
  --radius-selector: 0.5rem;
  --radius-field: 0.75rem;
  --radius-box: 1.25rem;
  --size-selector: 0.375rem;
  --size-field: 0.375rem;
  --border: 1.5px;
  --depth: 2;
  --noise: 1;
}</style>

Theme JSON Persistence

Save and load theme configurations as JSON files for easy reuse and sharing:

# Create a new custom theme for JSON save/load demonstration
neon_theme: ThemeConfig = {
    "name": "neon_nights",
    "default": False,
    "prefersdark": True,
    "color_scheme": "dark",
    "colors": {
        "base_100": "oklch(10% 0.02 260)",
        "base_200": "oklch(8% 0.02 260)",
        "base_300": "oklch(6% 0.02 260)",
        "base_content": "oklch(85% 0.15 320)",
        "primary": "oklch(70% 0.25 320)",
        "primary_content": "oklch(10% 0.02 320)",
        "secondary": "oklch(60% 0.22 180)",
        "secondary_content": "oklch(10% 0.02 180)",
        "accent": "oklch(75% 0.28 90)",
        "accent_content": "oklch(10% 0.02 90)",
        "neutral": "oklch(20% 0.03 260)",
        "neutral_content": "oklch(80% 0.10 320)",
        "info": "oklch(65% 0.20 220)",
        "info_content": "oklch(10% 0.02 220)",
        "success": "oklch(65% 0.22 150)",
        "success_content": "oklch(10% 0.02 150)",
        "warning": "oklch(72% 0.25 60)",
        "warning_content": "oklch(10% 0.02 60)",
        "error": "oklch(68% 0.25 15)",
        "error_content": "oklch(10% 0.02 15)"
    },
    "radius_selector": "0.25rem",
    "radius_field": "0.125rem",
    "radius_box": "0.5rem",
    "size_selector": "0.25rem",
    "size_field": "0.25rem",
    "border": "2px",
    "depth": 0.5,
    "noise": 0.2
}

# Save the theme as JSON
json_path = css_dir / f"{neon_theme['name']}.json"
save_theme_json(neon_theme, json_path)
print(f"Saved theme to: {json_path}")

# Verify the JSON file was created
print(f"\nJSON file contents:")
with open(json_path, 'r') as f:
    print(f.read()[:500] + "...")  # Show first 500 chars
Saved theme to: /mnt/SN850X_8TB_EXT4/Projects/GitHub/cj-mills/cjm-fasthtml-daisyui/css/neon_nights.json

JSON file contents:
{
  "name": "neon_nights",
  "default": false,
  "prefersdark": true,
  "color_scheme": "dark",
  "colors": {
    "base_100": "oklch(10% 0.02 260)",
    "base_200": "oklch(8% 0.02 260)",
    "base_300": "oklch(6% 0.02 260)",
    "base_content": "oklch(85% 0.15 320)",
    "primary": "oklch(70% 0.25 320)",
    "primary_content": "oklch(10% 0.02 320)",
    "secondary": "oklch(60% 0.22 180)",
    "secondary_content": "oklch(10% 0.02 180)",
    "accent": "oklch(75% 0.28 90)",
    "accent_content": "o...
# Load the theme back from JSON
loaded_theme = load_theme_json(json_path)

# Verify it loaded correctly
print(f"Loaded theme name: {loaded_theme['name']}")
print(f"Color scheme: {loaded_theme['color_scheme']}")
print(f"Primary color: {loaded_theme['colors']['primary']}")
print(f"Border radius (box): {loaded_theme['radius_box']}")

# Convert the loaded theme to CSS
loaded_css = create_theme_css(loaded_theme)
print(f"\nGenerated CSS from loaded theme (first 500 chars):")
print(loaded_css[:500] + "...")
Loaded theme name: neon_nights
Color scheme: dark
Primary color: oklch(70% 0.25 320)
Border radius (box): 0.5rem

Generated CSS from loaded theme (first 500 chars):
:root:has(input.theme-controller[value=neon_nights]:checked),[data-theme="neon_nights"] {
  color-scheme: dark;
  --color-base-100: oklch(10% 0.02 260);
  --color-base-200: oklch(8% 0.02 260);
  --color-base-300: oklch(6% 0.02 260);
  --color-base-content: oklch(85% 0.15 320);
  --color-primary: oklch(70% 0.25 320);
  --color-primary-content: oklch(10% 0.02 320);
  --color-secondary: oklch(60% 0.22 180);
  --color-secondary-content: oklch(10% 0.02 180);
  --color-accent: oklch(75% 0.28 90);
  --...
# Save the loaded theme as CSS to demonstrate the full workflow
css_from_json_path = css_dir / f"{loaded_theme['name']}_from_json.css"
save_theme_css(loaded_theme, css_from_json_path)

# Verify both CSS files have the same content
original_css = create_theme_css(neon_theme)
loaded_and_saved_css = Path(css_from_json_path).read_text()

print(f"CSS files match: {original_css == loaded_and_saved_css}")
print(f"\nWorkflow complete:")
print(f"1. Created theme configuration in Python")
print(f"2. Saved to JSON: {json_path}")
print(f"3. Loaded from JSON")
print(f"4. Generated CSS from loaded theme")
print(f"5. Saved CSS: {css_from_json_path}")
CSS files match: True

Workflow complete:
1. Created theme configuration in Python
2. Saved to JSON: /mnt/SN850X_8TB_EXT4/Projects/GitHub/cj-mills/cjm-fasthtml-daisyui/css/neon_nights.json
3. Loaded from JSON
4. Generated CSS from loaded theme
5. Saved CSS: /mnt/SN850X_8TB_EXT4/Projects/GitHub/cj-mills/cjm-fasthtml-daisyui/css/neon_nights_from_json.css

Export