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
Controlnode to your scene. This represents the item you will drag and drop.
- We need to visualize it, so add a
TextureRectnode 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/3Dnode because it can be anchored to ourControlcontainer.
- Add any texture (icon) to this
TextureRect.
- Attach a script to your
Controlnode. 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_previewto 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
CanvasLayernodes to your scene.
- Add a
Labelnode to the firstCanvasLayernode. Add aColorRectto the secondCanvasLayernode.
- Give the
Labelsome text, and change theColorRectscolor 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
CanvasLayernode has the sameLayervalue as the secondCanvasLayer. - Change the first
CanvasLayernode’sLayervalue 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
Controlnode to your scene. This will hold ourHBoxContainer. Change its size to something like 600px by 600px to give it a bounding area.
- Add a
HboxContainernode to thisControlnode. Also, make sure its anchor preset isfull_rectso that it takes up the entire space provided by theControlnode.
- Add three
Labelnodes 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
fillandexpand.
- Now your labels will be arranged horizontally across the entire 600px by 600px boundary box!
- To add some spacing between the items, select the
HBoxContainernode, 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
Controlnode to your scene. This will hold ourVBoxContainer. Change its size to something like 600px by 600px to give it a bounding area.
- Add a
VboxContainernode to thisControlnode. Also, make sure its anchor preset isfull_rectso that it takes up the entire space provided by theControlnode.
- Add three
Labelnodes 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
fillandexpand.
- Now your labels will be arranged horizontally across the entire 600px by 600px boundary box!
- To add some spacing between the items, select the
VBoxContainernode, 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
Controlnode to your scene. This will hold ourGridContainer. Change its size to something like 600px by 600px to give it a bounding area.
- Add a
GridContainernode to thisControlnode. Also, make sure its anchor preset isfull_rectso that it takes up the entire space provided by theControlnode.
- Add four
Labelnodes 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
GridContainernode. 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
fillandexpand.
- 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
GridContainernode, 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
CanvasLayernode to your scene. This will ensure that ourColorRectis drawn on our UI, so it can be displayed in the background.
- Add a
ColorRectnode to yourCanvasLayernode.
- Change its color, and change its anchor preset to be full_rect so that it takes up the entire screen.
- Change the
CanvasLayernode’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
Panelis used to create a panel for grouping UI elements, providing a background and border. It inherits fromControland 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
CanvasLayernode to your scene. This will ensure that ourPanelis drawn on our UI, so it can be displayed in the background.
- Add a
Panelnode to yourCanvasLayernode.
- 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
CanvasLayernode’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
CanvasModulatenode 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
CanvasLayernode to your scene. This will ensure that ourButtonis drawn on our UI, so it can be displayed at all times. - Add a
Buttonnode to yourCanvasLayernode.
- If you run your scene, your
Buttonshould 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
CanvasLayernode to your scene. This will ensure that ourLabelis drawn on our UI, so it can be displayed at all times. - Add a
Labelnode to yourCanvasLayernode.
- If you run your scene, your
Labelshould 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 Filtermode 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
CanvasLayernode to your scene. This will ensure that ourRichTextLabelis drawn on our UI, so it can be displayed at all times. - Add a
RichTextLabelnode to yourCanvasLayernode.
- Change its size to something like 200px by 200px.
- If you run your scene, your
RichTextLabelshould 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
AnimationPlayernode. 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 ratioproperty, 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
CanvasLayernode to your scene. This will ensure that ourProgressBarnode is drawn on our UI, so it can be displayed at all times. - Add a
ProgressBarnode to yourCanvasLayernode.
- Change its size to something like 200px by 27px, and enable its
Roundedvalue so it only shows whole numbers.
- To be able to increase our
ProgressBar, we should add aTimernode. Enable this timer node’sautostartproperty, and connect itstimeoutsignal 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.
