Skip to content

Styling

Castella provides a comprehensive theming system with design tokens (colors, typography, spacing) and per-widget styling options.

Theme System

The theme system is located in castella.theme and provides:

  • ColorPalette: All color definitions (backgrounds, text, borders)
  • Typography: Font settings (family, size, scale)
  • Spacing: Layout measurements (padding, margin, border radius)
  • ThemeManager: Singleton for dynamic theme switching

Automatic Theming

Castella automatically detects dark/light mode from the operating system and applies appropriate colors.

Built-in Themes

Castella includes several professionally designed themes:

Theme Style Border Radius Font
Tokyo Night (default) Purple/blue aesthetic 6px JetBrains Mono
Cupertino Apple-inspired design 8px SF Pro / Helvetica Neue
Material Design 3 Google's Material design 12px Roboto
Castella Dark Neon colors on dark 0px System default
Castella Light Soft pastels on light 0px System default

Environment Variables

Override the automatic theme detection:

Variable Values Description
CASTELLA_DARK_MODE true / false Force dark or light mode
CASTELLA_FONT_SIZE Integer (e.g., 14) Override default font size
# Force dark mode
CASTELLA_DARK_MODE=true python my_app.py

# Use larger font
CASTELLA_FONT_SIZE=18 python my_app.py

Using ThemeManager

Get Current Theme

from castella.theme import ThemeManager

manager = ThemeManager()
theme = manager.current

print(f"Theme: {theme.name}")
print(f"Is dark: {theme.is_dark}")
print(f"Background: {theme.colors.bg_canvas}")

Toggle Dark/Light Mode

from castella import Button
from castella.theme import ThemeManager

manager = ThemeManager()

# Toggle button
Button("Toggle Theme").on_click(lambda _: manager.toggle_dark_mode())

Force Dark or Light Mode

# Force dark mode
manager.prefer_dark(True)

# Force light mode
manager.prefer_dark(False)

# Return to automatic detection
manager.prefer_dark(None)

Using Different Built-in Themes

from castella.theme import (
    ThemeManager,
    CUPERTINO_DARK_THEME, CUPERTINO_LIGHT_THEME,
    MATERIAL_DARK_THEME, MATERIAL_LIGHT_THEME,
    TOKYO_NIGHT_DARK_THEME, TOKYO_NIGHT_LIGHT_THEME,
    DARK_THEME, LIGHT_THEME,  # Classic Castella themes
)

manager = ThemeManager()

# Use Material Design theme
manager.set_dark_theme(MATERIAL_DARK_THEME)
manager.set_light_theme(MATERIAL_LIGHT_THEME)

# Or Cupertino (Apple-style) theme
manager.set_dark_theme(CUPERTINO_DARK_THEME)
manager.set_light_theme(CUPERTINO_LIGHT_THEME)

Custom Themes

Derive from Existing Theme

The easiest way to customize is using Theme.derive() for partial overrides:

from castella.theme import ThemeManager, DARK_THEME

# Override just a few colors
custom = DARK_THEME.derive(
    colors={
        "border_primary": "#00ff00",  # Green borders
        "text_info": "#00ffff",       # Cyan info text
        "bg_overlay": "#ff6b6b",      # Custom hover color
    },
    typography={
        "base_size": 16,              # Larger font
    },
)

manager = ThemeManager()
manager.set_dark_theme(custom)

Create Complete Custom Theme

For full control, create a new ColorPalette:

from castella.theme import (
    Theme,
    ColorPalette,
    Typography,
    Spacing,
    ThemeManager,
)

# Cyberpunk theme
cyberpunk_palette = ColorPalette(
    # Backgrounds
    bg_canvas="#0a0a0a",
    bg_primary="#0a0a0a",
    bg_secondary="#121212",
    bg_tertiary="#1a1a2e",
    bg_overlay="#00ff41",
    bg_info="#0a0a0a",
    bg_danger="#0a0a0a",
    bg_success="#0a0a0a",
    bg_warning="#0a0a0a",
    bg_pushed="#1a1a2e",
    bg_selected="#00ff41",
    # Text
    fg="#00ff41",
    text_primary="#00ff41",
    text_info="#00d4ff",
    text_danger="#ff0055",
    text_success="#00ff41",
    text_warning="#ffff00",
    # Borders
    border_primary="#00ff41",
    border_secondary="#00d4ff",
    border_info="#00d4ff",
    border_danger="#ff0055",
    border_success="#00ff41",
    border_warning="#ffff00",
)

cyberpunk_theme = Theme(
    name="cyberpunk",
    is_dark=True,
    colors=cyberpunk_palette,
    typography=Typography(base_size=14),
    spacing=Spacing(),
    code_pygments_style="monokai",
)

manager = ThemeManager()
manager.set_dark_theme(cyberpunk_theme)
manager.prefer_dark(True)

Widget Kinds

Many widgets support the kind parameter for semantic coloring:

from castella import Text, Button, Kind

# Text with different kinds
Text("Normal text", kind=Kind.NORMAL)   # Default styling
Text("Info message", kind=Kind.INFO)    # Cyan/blue tones
Text("Success!", kind=Kind.SUCCESS)     # Green tones
Text("Warning!", kind=Kind.WARNING)     # Yellow/amber tones
Text("Error!", kind=Kind.DANGER)        # Red/pink tones

# Buttons with different kinds
Button("Normal", kind=Kind.NORMAL)      # Default button
Button("Info", kind=Kind.INFO)          # Info-styled button
Button("Success", kind=Kind.SUCCESS)    # Success-styled button
Button("Warning", kind=Kind.WARNING)    # Warning-styled button
Button("Danger", kind=Kind.DANGER)      # Danger-styled button

# Fluent API also works
Button("Delete").kind(Kind.DANGER)

Available Kinds

Kind Use Case Dark Theme Colors
Kind.NORMAL Default content Light gray text
Kind.INFO Informational messages Neon cyan
Kind.SUCCESS Success states Neon green
Kind.WARNING Warnings, caution Neon yellow
Kind.DANGER Errors, destructive actions Neon red

Per-Widget Styling

Background and Text Colors

Override colors on individual widgets:

# Custom background color
Text("Custom").bg_color("#ff0000")

# Custom text color
Text("Custom").text_color("#ffffff")

# Both
Text("Custom").bg_color("#1a1a2e").text_color("#eee")

Border Styling

# Set border color
widget.border_color("#ff00ff")

# Make border match background (effectively hides it)
widget.erase_border()

Text Alignment

Control text alignment within widgets:

from castella import Text
from castella.models.style import TextAlign

Text("Left aligned", align=TextAlign.LEFT)
Text("Centered", align=TextAlign.CENTER)   # Default
Text("Right aligned", align=TextAlign.RIGHT)

Design Tokens Reference

ColorPalette Properties

Property Description
bg_canvas Main application background
bg_primary Primary widget background
bg_secondary Secondary widget background
bg_tertiary Tertiary/accent background
bg_overlay Overlay/hover background
bg_pushed Button pressed state
bg_selected Selected item background
bg_info Info kind background
bg_danger Danger kind background
bg_success Success kind background
bg_warning Warning kind background
fg Default foreground
text_primary Primary text
text_info Info kind text
text_danger Danger kind text
text_success Success kind text
text_warning Warning kind text
border_primary Primary border
border_secondary Secondary border
border_info Info kind border
border_danger Danger kind border
border_success Success kind border
border_warning Warning kind border

Typography Properties

Property Default Description
font_family "" (system) Font family name
font_family_mono "monospace" Monospace font for code
base_size 14 Base font size in pixels
scale_ratio 1.25 Ratio for heading size calculation

Use typography.heading_size(level) to get computed heading sizes.

Spacing Properties

Property Default Description
padding_sm 4 Small padding
padding_md 8 Medium padding
padding_lg 16 Large padding
margin_sm 4 Small margin
margin_md 8 Medium margin
margin_lg 16 Large margin
border_radius 4 Border corner radius
border_width 1.0 Border line width

Built-in Theme Colors

Tokyo Night (Default)

# Dark variant
{
    "bg_canvas": "#1a1b26",      # Deep blue-black
    "fg": "#c0caf5",             # Light purple-white
    "text_info": "#7dcfff",      # Cyan
    "text_danger": "#f7768e",    # Red
    "text_success": "#9ece6a",   # Green
    "text_warning": "#e0af68",   # Yellow
    "border_primary": "#565f89", # Muted purple
}

Material Design 3

# Dark variant
{
    "bg_canvas": "#121212",      # Material dark surface
    "fg": "#e1e1e1",             # On-surface
    "text_info": "#82b1ff",      # Light blue
    "text_danger": "#cf6679",    # Error
    "text_success": "#81c784",   # Light green
    "text_warning": "#ffb74d",   # Orange
    "border_primary": "#444444", # Outline
}

Cupertino (Apple-style)

# Dark variant
{
    "bg_canvas": "#1e1e1e",      # Window background
    "fg": "#ffffff",             # Primary label
    "text_info": "#64d2ff",      # System Cyan
    "text_danger": "#ff6961",    # System Red
    "text_success": "#30d158",   # System Green
    "text_warning": "#ffd60a",   # System Yellow
    "border_primary": "#48484a", # Separator
}

Example: Theme Demos

Run the theme demos to see all features in action:

# Tokyo Night theme demo (default)
uv run python examples/tokyo_night_theme_demo.py

# Cupertino (Apple-style) theme demo
uv run python examples/cupertino_theme_demo.py

# Material Design 3 theme demo
uv run python examples/material_theme_demo.py

These examples demonstrate:

  • Dark/light mode toggle
  • Theme switching between different styles
  • Button Kind variants (Normal, Info, Success, Warning, Danger)
  • Rounded corners and modern UI aesthetics
  • Typography and spacing information display