godot-ui-theming
UI Theming
Theme resources, StyleBox styling, font management, and override system define consistent UI visual identity.
Available Scripts
global_theme_manager.gd
Expert theme manager with dynamic switching, theme variants, and fallback handling.
ui_scale_manager.gd
Runtime theme switching and DPI/Resolution scale management.
theme_swapper.gd
Dynamic Dark/Light mode implementation using cascading theme root propagation.
danger_button_assignment.gd
Expert use of theme_type_variation for semantic UI styling without scene duplication.
dynamic_stylebox_color.gd
Safe runtime StyleBox modification. Demonstrates the critical duplicate() pattern for isolated overrides.
procedural_theme_safe.gd
Reliable theming for generated UI elements using NOTIFICATION_THEME_CHANGED.
custom_chart_drawing.gd
Pattern for reading active Theme properties (colors, fonts) in custom _draw() logic.
theme_isolation.gd
Ensuring HUD consistency by isolating nodes from parent themes and referencing Project Defaults.
pulsating_ui_theme.gd
Animating UI styles via Tweens. Targets StyleBox properties directly after duplication.
crisp_ui_scaler.gd
High-quality resolution-independent scaling using content_scale_factor to maintain font crispness.
memory_safe_custom_drawing.gd
Fixing the "disappearing stylebox" bug by caching resources at the class level for the RenderingServer.
rtl_theme_mirroring.gd
Bi-directional (RTL/LTR) UI support. Swaps theme variants dynamically based on layout direction.
NEVER Do in UI Theming
- NEVER create StyleBox in
_ready()for many nodes — InstantiatingStyleBoxFlat.new()100 times creates 100 unique objects. Use a Theme resource for shared heritage. - NEVER forget theme inheritance — Parent themes are ignored if a child has its own theme. Apply themes at the root and use
theme_type_variationfor specific overrides. - NEVER hardcode colors in StyleBox — Use
theme.get_color()to maintain a single source of truth for your palette. - NEVER use
add_theme_overridefor global styles — This is brittle. Define styles in a Theme resource for automatic propagation across the project. - NEVER modify theme resources during
_draw()OR_process()— Frequent layout recalculations will severely degrade performance. - NEVER assign
StyleBoxEmptyto focus styles without a fallback — This invisibly breaks controller/keyboard navigation [1]. Always provide a visible alternative (e.g. scale change). - NEVER use standard
set()for theme properties — Callingnode.set("font_color", red)fails. You MUST use the dedicatedadd_theme_color_override()API [3]. - NEVER use
expand_margin_*to increase clickable area — It only expands the VISUAL bounds. Usecontent_margin_*on the StyleBox or adjust the Control's size to ensure input works [5]. - NEVER define StyleBoxes as local variables inside
_draw()— They will be garbage collected before the RenderingServer can finish drawing them [7]. Store at class level. - NEVER duplicate scenes/themes just to change one color — Use
theme_type_variationto create lightweight derived styles (e.g. "DangerButton") within the same Theme [8]. - NEVER skip
corner_radius_allshortcut — It's a useful shorthand for uniform rounding inStyleBoxFlat.
- Project Settings → GUI → Theme
- Create new Theme resource
- Assign to root Control node
- All children inherit theme
StyleBox Pattern
# Create StyleBoxFlat for buttons
var style := StyleBoxFlat.new()
style.bg_color = Color.DARK_BLUE
style.corner_radius_top_left = 5
style.corner_radius_top_right = 5
style.corner_radius_bottom_left = 5
style.corner_radius_bottom_right = 5
# Apply to button
$Button.add_theme_stylebox_override("normal", style)
Font Loading
# Load custom font
var font := load("res://fonts/my_font.ttf")
$Label.add_theme_font_override("font", font)
$Label.add_theme_font_size_override("font_size", 24)
Reference
Related
- Master Skill: godot-master