The Book of Nodes: UI
Below you can find a list of UI nodes that can be used in Godot 4. This is part of my Book of Nodes series. If you want to see similar content on 2D or 3D nodes, please refer to the parent page of this post for those links. 😊
Before we begin, if you need a base project to test these code snippets, feel free to download my FREE 2D and 3D templates here. I’ll be using these templates throughout this post.
*Please note that this list is NOT 100% complete yet, but I will be updating this list as time goes on.
- Control
- CanvasLayer
- CanvasModulate
- Container
- HBoxContainer
- VBoxContainer
- GridContainer
- ColorRect
- Panel
- Button
- Label
- RichTextLabel
- ProgressBar
Common Properties
Anchoring
- Determines how a UI element is positioned and resized relative to its parent container.
anchor_left
: Sets the left anchor point (0 to 1).anchor_top
: Sets the top anchor point (0 to 1).anchor_right
: Sets the right anchor point (0 to 1).anchor_bottom
: Sets the bottom anchor point (0 to 1).full_rect
: Sets the anchor point to all sides.
Margins
- Defines the distance between the UI element and its parent container’s edges.
margin_left
: Distance from the left edge.margin_top
: Distance from the top edge.margin_right
: Distance from the right edge.margin_bottom
: Distance from the bottom edge.
Font
- Customizes the appearance of text within UI elements.
font
: The font resource used for the text.font_size
: The size of the font.font_color
: The color of the font.
Color
- Customize the color properties of UI elements.
color
: The main color of the UI element.font_color
: The color of the text.modulate
: The alpha value applied to the UI element.
Transform
- Controls the position, rotation, and scale of UI elements.
position
: The position of the UI element.rotation
: The rotation of the UI element in degrees.scale
: The scale of the UI element.
Size Flags
- Determines how a UI element resizes within its parent container.
size_flags_horizontal
: Horizontal resizing behavior (e.g., fill, expand).size_flags_vertical
: Vertical resizing behavior (e.g., fill, expand).
Visibility
- Controls the visibility of UI elements.
visible
: Whether the UI element is visible.self_modulate
: The color modulation applied to the UI element, affecting its visibility.
Focus
- Manages keyboard and controller focus for UI elements.
focus_mode
: Determines if the UI element can receive focus (none, click, all).focus_neighbour_*
: Specifies neighboring UI elements for focus navigation (up, down, left, right).
Tooltip
- Provides additional information when the user hovers over a UI element.
hint_tooltip
: The text displayed as a tooltip.
Theme Overrides
- Allows customization of the UI element’s appearance beyond the default theme.
theme
: The theme resource applied to the UI element.theme_type_variation
: A variation of the theme type for more specific customization.
Control
A Control
node provides a bounding rectangle on the viewport that can be used for creating user interfaces in Godot, as they handle input events, focus, and other UI-specific functionalities.
Mechanic:
Drag and drop a sprite on the map.
Implementation:
- Add a
Control
node to your scene. This represents the item you will drag and drop.
- We need to visualize it, so add a
TextureRect
node to it. This node allows us to add a sprite to the control so that we can see what we are moving. This works better than theSprite2D/3D
node because it can be anchored to ourControl
container.
- Add any texture (icon) to this
TextureRect
.
- Attach a script to your
Control
node. To be able to drag and drop this object, we will need to connect itsgui_input()
signal to our script.
- In your code, add the functionality to select the item using the LEFT mouse button. Use
set_drag_preview
to show a visual representation of the item being dragged. - Then, add the functionality to drop your item on the LEFT mouse button release.
- And then also add the functionality to snap the item to your mouse cursor whilst dragging it around.
### Control.gd
extends Control
var drag_offset = Vector2.ZERO
var is_dragging = false
func _on_gui_input(event):
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
# Select
if event.pressed:
is_dragging = true
if get_viewport().gui_is_dragging():
set_drag_preview(self)
else:
# Drop
is_dragging = false
# Drag
elif event is InputEventMouseMotion and is_dragging:
var global_pos = get_global_mouse_position()
global_position = global_pos - size / 2
- Test your logic by selecting the item and dragging it around.
CanvasLayer
A CanvasLayer
is used for independent rendering of objects within a 2D scene, often for UI elements or HUDs. It renders its child nodes independently of the main scene's camera, which means that they remain fixed on the screen.
Example Use Cases:
- HUD (Heads-Up Display).
- Fixed-position UI elements.
- Overlay menus.
Mechanic:
To demonstrate the use of the layer
property, we will create a simple scene with two CanvasLayer nodes. One will be used for a background layer, and the other for a UI layer. The background layer will be drawn behind the UI layer.
Implementation:
- Add two
CanvasLayer
nodes to your scene.
- Add a
Label
node to the firstCanvasLayer
node. Add aColorRect
to the secondCanvasLayer
node.
- Give the
Label
some text, and change theColorRects
color to a dark grey. Also, change its anchor-preset to be full_rect.
- You will see that our label isn’t showing, because our first
CanvasLayer
node has the sameLayer
value as the secondCanvasLayer
. - Change the first
CanvasLayer
node’sLayer
value to be “2”.
- Your label should now be on top of the background!
Container
A Container
is used to organize UI elements, providing a base class for various container types. It inherits from Control
and provides functionality for arranging child nodes. We usually don’t use this node a lot, as a normal Control
node suffices.
You might, however, use a ScrollContainer
node. A ScrollContainer
is a type of container node in Godot that provides scrollbars to its child control when needed. It is useful for creating scrollable areas in your UI, such as lists, text areas, or any content that exceeds the visible area of the container.
Example Use Cases:
- Base class for custom container types.
- Organizing complex UI layouts.
- Creating custom layout behaviors.
HBoxContainer
An HBoxContainer
is used to arrange UI elements horizontally. It inherits from Container
and arranges its children in a horizontal line.
Example Use Cases:
- Horizontal menus.
- Toolbars.
- Row-based layouts.
Mechanic:
Arrange a list of items horizontally on the scene.
Implementation:
- Add a
Control
node to your scene. This will hold ourHBoxContainer
. Change its size to something like 600px by 600px to give it a bounding area.
- Add a
HboxContainer
node to thisControl
node. Also, make sure its anchor preset isfull_rect
so that it takes up the entire space provided by theControl
node.
- Add three
Label
nodes to theHBoxContainer
.
- You will see that the items stack next to each other, but they don’t take up the entire space. To fix this, we will need to set their container sizing properties to
fill
andexpand
.
- Now your labels will be arranged horizontally across the entire 600px by 600px boundary box!
- To add some spacing between the items, select the
HBoxContainer
node, and change its separation constant to a value such as 10.
VBoxContainer
A VBoxContainer
is used to arrange UI elements vertically. It inherits from Container
and arranges its children in a vertical line.
Example Use Cases:
- Vertical settings menus.
- Stacked buttons.
- Column-based layouts.
Mechanic:
Arrange a list of items vertically on the scene.
Implementation:
- Add a
Control
node to your scene. This will hold ourVBoxContainer
. Change its size to something like 600px by 600px to give it a bounding area.
- Add a
VboxContainer
node to thisControl
node. Also, make sure its anchor preset isfull_rect
so that it takes up the entire space provided by theControl
node.
- Add three
Label
nodes to theVBoxContainer
.
- You will see that the items stack on top of each other, but they don’t take up the entire space. To fix this, we will need to set their container sizing properties to
fill
andexpand
.
- Now your labels will be arranged horizontally across the entire 600px by 600px boundary box!
- To add some spacing between the items, select the
VBoxContainer
node, and change its separation constant to a value such as 10.
GridContainer
A GridContainer
is used to arrange UI elements in a grid. It inherits from Container
and arranges its children in a grid layout.
Example Use Cases:
- Keypads.
- Control panels.
- Inventory grids.
Mechanic:
Arrange a list of items in a grid on the scene.
Implementation:
- Add a
Control
node to your scene. This will hold ourGridContainer
. Change its size to something like 600px by 600px to give it a bounding area.
- Add a
GridContainer
node to thisControl
node. Also, make sure its anchor preset isfull_rect
so that it takes up the entire space provided by theControl
node.
- Add four
Label
nodes to theGridContainer
.
- You will see that the items stack on top of each other, instead of in a grid. To fix this, we will need to up our columns property in our
GridContainer
node. Change this value to 2.
- Now they are arranged in the grid, but they don’t take up the entire space. To fix this, we will need to set their container sizing properties to
fill
andexpand
.
- Now your labels will be arranged in a grid format across the entire 600px by 600px boundary box!
- To add some spacing between the items, select the
GridContainer
node, and change its separation constant to a value such as 10.
ColorRect
A ColorRect
is used to display a solid color rectangle, often for backgrounds or color overlays. It inherits from Control
and provides a simple way to display a rectangle filled with a specified color. The color can be set and changed dynamically.
Example Use Case:
- Background overlays.
- Progress bars.
- Color indicators.
Mechanic:
Add a background color to your scene.
Implementation:
- Add a
CanvasLayer
node to your scene. This will ensure that ourColorRect
is drawn on our UI, so it can be displayed in the background.
- Add a
ColorRect
node to yourCanvasLayer
node.
- Change its color, and change its anchor preset to be full_rect so that it takes up the entire screen.
- Change the
CanvasLayer
node’s layer property to something like -1 so that it is displayed behind our other nodes. We should now have a background color!
Panel
- A
Panel
is used to create a panel for grouping UI elements, providing a background and border. It inherits fromControl
and provides a simple way to group and visually separate UI elements.
Example Use Case:
- Settings panels.
- Dialog boxes.
- Grouping related UI elements.
Mechanic:
Add a background color to your scene.
Implementation:
- Add a
CanvasLayer
node to your scene. This will ensure that ourPanel
is drawn on our UI, so it can be displayed in the background.
- Add a
Panel
node to yourCanvasLayer
node.
- To change its color, we’ll need to give it a new theme style of type StyleBoxFlat.
- Now we can give it a new color, border, and even a shadow!
- Change its anchor preset to full_rect so that it takes up the entire screen.
- Change the
CanvasLayer
node’s layer property to something like -1 so that it is displayed behind our other nodes. We should now have a background color!
CanvasModulate
A CanvasModulate
applies a color tint to all nodes on a canvas. It tints the canvas elements using its assigned color.
Example Use Cases:
- Night mode effect.
- Global color adjustments.
- Visual effects for different game states.
Mechanic:
Add a day-and-night cycle to your game
Implementation:
- Add a
CanvasModulate
node to your scene.
- If you change its color property, the entire scene's color should change.
- We want to animate this property. So, add an AnimationPlayer node to your scene.
- Create a new animation called
day_night_cycle
. Set the length of this animation to be 24 seconds long. This will make our day 24 seconds long (for 24 hours).
- Also, enable looping.
- Now add a color keyframe for every 6 hours (or whatever preference you have). These colors should represent the colors from 0 AM to 24 PM.
- On my timeline, my colors are:
0: #0f0a49
6: #7b5436
12: #ffffff
18: #5b6a99
24: #0f0a49
- Now when we run our game, we should play this animation.
### Main.gd
extends Node2D
@onready var animation_player = $AnimationPlayer
func _ready():
animation_player.play("day_night_cycle")
- If you want a better tutorial using shaders, check out the video on my YouTube channel!
Button
A Button
is used to create a clickable button for user interactions. It inherits from BaseButton
and provides functionality for detecting clicks and triggering actions.
If you want to use a button that has a texture (image) and more customizability, you should use a TextureButton
node. The TextureButton node is a button that uses textures for its different states (normal, pressed, hover, etc.) instead of the default theme. This allows for more customized and visually appealing buttons. It inherits from BaseButton
and provides properties to set textures for different states.
Example Use Cases:
- Interactive buttons.
- Menu options.
- Form submissions.
Mechanic:
Add a clickable button to your scene.
Implementation:
- Add a
CanvasLayer
node to your scene. This will ensure that ourButton
is drawn on our UI, so it can be displayed at all times. - Add a
Button
node to yourCanvasLayer
node.
- If you run your scene, your
Button
should be visible.
- Now, attach its
pressed()
signal function to your script.
- If we press the button, we will change its text. We will keep track of the times we’ve pressed it and update it each time we press the button.
### Main.gd
extends Node2D
@onready var button = $CanvasLayer/Button
var button_pressed_count = 0
func _on_button_pressed():
button_pressed_count += 1
button.text = "You've pressed me: " + str(button_pressed_count) + " times!"
- Every time you press the button, the count should update!
Label
A Label
is used to display text. It inherits from Control
and provides functionality for displaying text.
Example Use Cases:
- Static text display.
- Descriptive labels.
- Titles and headings.
Mechanic:
Add a label that changes its text when you hover over it.
Implementation:
- Add a
CanvasLayer
node to your scene. This will ensure that ourLabel
is drawn on our UI, so it can be displayed at all times. - Add a
Label
node to yourCanvasLayer
node.
- If you run your scene, your
Label
should be visible.
- Now, let’s make it more visible. Change its font color to be red, and its size to something like 25px.
- Since we want it to detect mouse events, we need to change its
Mouse Filter
mode toPass
.
- Now, to detect that we are hovering over it, we need to attach its
mouse_entered()
andmouse_exited()
signals to our script.
- Then, simply change the text when we enter and exit the label while hovering! If you run your game, the label should change depending on whether or not you are hovering over it.
### Main.gd
extends Node2D
@onready var label = $CanvasLayer/Label
func _on_label_mouse_entered():
label.text = "You're hovering over a label"
func _on_label_mouse_exited():
label.text = "You're away from the label"
RichTextLabel
A RichTextLabel
is used to display formatted text. It inherits from Control
and provides functionality for displaying rich text with formatting, such as bold, italics, and images.
Example Use Cases:
- Formatted text display.
- Dialogue boxes.
- Instructional text.
Mechanic:
Write words in a typewriter effect.
Implementation:
- Add a
CanvasLayer
node to your scene. This will ensure that ourRichTextLabel
is drawn on our UI, so it can be displayed at all times. - Add a
RichTextLabel
node to yourCanvasLayer
node.
- Change its size to something like 200px by 200px.
- If you run your scene, your
RichTextLabel
should be visible.
- Now, let’s make it more visible. Change its font color to red, and its size to something like 25px.
- To create our typewriter animation, we will need to use an
AnimationPlayer
node. Add this node to your scene.
- Create a new animation called
typewriter
.
- To create a typewriter effect, we need to animate our RichTextLabel node’s
visible ratio
property, which defines how much of our text is visible.
- At the 0 keyframe mark, set your visible ratio to be equal to 0.
- At the 1 keyframe mark, set your visible ratio to be equal to 1. This means in 1 second, our text will go from no characters to full characters.
- Now if you play your animation, your text should play as if it's being typed out.
ProgressBar
ProgressBar is a UI element that visually represents a value within a range. It inherits from the Range
class, which provides properties like min_value
, max_value
, and value
to control the progress.
Example Use Cases:
- Loading screens.
- Health bars.
- Progress indicators.
Mechanic:
Create a health bar that increases every 1 second, and when we press SPACE, it decreases in value.
Implementation:
- Add a
CanvasLayer
node to your scene. This will ensure that ourProgressBar
node is drawn on our UI, so it can be displayed at all times. - Add a
ProgressBar
node to yourCanvasLayer
node.
- Change its size to something like 200px by 27px, and enable its
Rounded
value so it only shows whole numbers.
- To be able to increase our
ProgressBar
, we should add aTimer
node. Enable this timer node’sautostart
property, and connect itstimeout
signal to your script.
- Whenever it times out (every 1 second its active), we will increase our “health” value.
### Main.gd
extends Node2D
@onready var progress_bar = $CanvasLayer/ProgressBar
func _on_timer_timeout():
progress_bar.value += 1
- Whenever we press our SPACE bar, we should decrease our health value.
### Main.gd
extends Node2D
@onready var progress_bar = $CanvasLayer/ProgressBar
func _on_timer_timeout():
progress_bar.value += 1
func _input(event):
if event.is_action_pressed("ui_accept"):
progress_bar.value -= 5
- Now if we run our scene, our health should increase every second, but decrease when we press our button.